当前位置: 首页 > 编程语言 > C#

ConvertingAsync-AwaitC#CodetoScheduler-RelatedF#分享

时间:2023-04-10 16:35:09 C#

ConvertingAsync-AwaitC#CodetoScheduler-RelatedF#不知道这个问题是不是太笼统了,不过最近让自己碰到了一块我试图确定如何从C#转换为正确的F#的代码。旅程从这里开始(1)(关于TPL-F#交互的原始问题),并从这里继续(2)(我正在考虑转换为F#的一些示例代码)。示例代码太长,无法在此处重现,但有趣的函数是ActivateAsync、RefreshHubs和AddHub。特别有趣的是,AddHub有一个privateasyncTaskAddHub(stringaddress)的签名。RefreshHubs在循环中调用AddHub并收集任务列表,然后通过awaitTask.WhenAll(tasks)它最终等待Task.WhenAll(tasks)因此返回值与其私有异步任务RefreshHubs(object_)签名匹配。RefreshHubs像awaitRefreshHubs(null)一样由ActivateAsync调用,最后调用awaitbase.ActivateAsync()匹配函数签名publicoverrideasyncTaskActivateAsync()。问题:将这些函数签名转换为F#并仍然保留接口和函数并尊重默认自定义调度程序的正确方法是什么?我不太确定这个“F#中的异步/等待”。至于如何“机械地”去做。?原因是在链接“here(1)”中似乎存在问题(我尚未验证),因为F#异步操作不遵守(Orleans)运行时设置的自定义协作调度程序。?此外,这里声明TPL操作会脱离调度程序并进入任务池,因此禁止使用它们。我能想到解决这个问题的一种方法是使用F#函数,如下所示//对于缩短代码给您带来的不便,我们深表歉意,有关上下文,请参阅链接“此处(1)”...覆盖此.ActivateAsync()=this.RegisterTimer(newFunc(this.FlushQueue),null,TimeSpan.FromMilliseconds(100.0),TimeSpan.FromMilliseconds(100.0))|>如果RoleEnvironment.IsAvailable则忽略this.RefreshHubs(null)|>Async.awaitPlainTask|>Async.RunSynchronouslyelsethis.AddHub("http://localhost:48777/")|>Async.awaitPlainTask|>Async.RunSynchronously//返回值来自这里。base.ActivateAsync()memberprivatethis.RefreshHubs(_)=//代码省略,如果需要mor上下文,看一下链接“这里(2)”,不便之处请见谅...//返回值为任务。//在C#版本中,收集AddHub提供的任务,然后//在最后一行有returnawaitTask.WhenAll(newHubAdditionTasks)newHubs|>Array.map(funi->this.AddHub(i))|>Task.WhenAll成员公关ivatethis.AddHub(address)=//代码省略,如果需要更多上下文,请查看链接“这里(2)”,不便之处请见谅...//在C#版本中://。..//hubs.Add(address,newTuple(hubConnection,hub))//}//所以这是“空的”,在F#中可能是异步的...//返回值是Task.hubConnection.Start()|>Async.awaitTaskVoid|>Async.RunSynchronouslyTaskDone.DonestartAsPlainTask函数,作者:SachaBarber从这里开始另一个有趣的选项可能在这里编辑:我刚刚注意到Task.WhenAll也需要等待。但正确的方法是什么?呃,该睡觉了(坏双关语)......<编辑2:在Codeplex中,此处(1)(TPL-F#Interaction的原始问题),提到F#使用同步上下文将工作推送到线程,而TPL则没有。现在,我认为这是一个似是而非的解释(尽管无论自定义调度程序如何,我仍然无法正确翻译这些片段)。一些有趣的附加信息可能来自我认为在这种情况下,我需要提及Hopac作为一个有趣的切线,并且还提到我在接下来的50个小时左右无法联系到我,以防我所有的交叉发布都失去控制。<编辑3:Daniel和svick在评论中提供了使用自定义任务生成器的很好的建议。Daniel提供了一个已经在FSharpx中定义的链接。查看源代码,我看到带参数的接口定义为类型TaskBuilder(?continuationOptions,?scheduler,?cancellationToken)=letcontOptions=defaultArgcontinuationOptionsTaskContinuationOptions.Noneletscheduler=defaultArgschedulerTaskScheduler.DefaultletcancellationTokenCancellationToken=defaultArgenIf您将在Orleans中使用它,看起来TaskScheduler应该是TaskScheduler.Current,根据这里的文档,Orleans有自己的任务调度程序,它提供了grain中使用的单线程执行模型。重要的是在运行任务时使用Orleans调度程序,而不是.NET线程池。如果你的grain代码需要创建子任务,你应该使用Task.Factory.StartNew:awaitTask.Factory.StartNew(()=>{/*logic*/});该技术将使用当前的任务调度程序,即Orleans调度程序。您应该避免使用Task.Run,??它始终使用.NET线程池,因此不会在单线程执行模型中运行。看起来TaskScheduler.Current和TaskScheduler.Default之间略有不同。也许这需要一个问题,在这种情况下会出现意想不到的差异。由于Orleans文档声明不使用Task.Run而是直接使用Task.Factory.StartNew,我想知道我是否应该定义TaskCreationOptions.DenyAttachChild,正如StephenToub等权威人士在Task.Run与Task.Factory上所建议的那样。StartNew和StartNew的StephenCleary是危险人物。嗯,看起来.Default将是.DenyAttachChilld,除非我弄错了。此外,由于Task.RunTask.Factory.CreateNew在自定义调度程序方面存在问题,我想知道我是否可以通过使用自定义TaskFactory来解决此特定问题,如TaskScheduler(Task.Factory)中所述,并控制该线程数和操作方法:创建一个限制并发的任务调度器。好吧,这已经成为一个长期的“想法”。我想知道我应该如何关闭它?也许如果svick和Daniel可以将他们的评论作为答案,我也会投票并接受svick的评论吗?可以在FSharpx中使用TaskBuilder,传入TaskScheduler.Current。这是我翻译RefreshHubs的尝试。请注意,这里使用的是Task而不是Task。以上就是《C#学习教程:异步等待C#代码转F#调度器相关》的全部内容。如果对你有用,需要进一步了解C#学习教程,希望大家多多关注——letRefreshHubs_=lettask=TaskBuilder(scheduler=TaskScheduler.Current)task{letaddresses=RoleEnvironment.Roles.["GPSTracker.Web"].Instances|>Seq.map(funinstance->letendpoint=instance.InstanceEndpoints.["InternalSignalR"]sprintf"http://%O"endpoint.IPEndpoint)|>Seq.toListletnewHubs=地址|>List.filter(notSeq.filter(funx->not(List.exists((=)x)addresses))//删除死集线器deadHubs|>Seq.iter(hubs.Remove>>ignore)//添加新的hubslet!_=Task.WhenAll[|forhubinnewHubs->AddHubhub|]return()}本文收集自网络,不代表立场,如涉及侵权,请点击有权联系管理员删除,如需转载请注明出处: