C# 针对调度程序将异步等待C代码转换为F代码
我不知道这是否是一个太宽泛的问题,但最近我遇到了一段代码,我想确定如何将C#翻译成适当的F#。旅程从(TPL-F#交互的原始问题)开始,然后继续(我正在考虑将一些示例代码翻译成F#) 示例代码太长,无法在此处重现,但有趣的函数有C# 针对调度程序将异步等待C代码转换为F代码,c#,f#,task-parallel-library,c#-to-f#,orleans,C#,F#,Task Parallel Library,C# To F#,Orleans,我不知道这是否是一个太宽泛的问题,但最近我遇到了一段代码,我想确定如何将C#翻译成适当的F#。旅程从(TPL-F#交互的原始问题)开始,然后继续(我正在考虑将一些示例代码翻译成F#) 示例代码太长,无法在此处重现,但有趣的函数有ActivateAsync、RefreshHubs和AddHub。特别有趣的是 AddHub的签名为private async Task AddHub(字符串地址) RefreshHubs在循环中调用AddHub,并收集任务列表,然后在最后通过wait Task等待任务。
ActivateAsync
、RefreshHubs
和AddHub
。特别有趣的是
AddHub
的签名为private async Task AddHub(字符串地址)
RefreshHubs
在循环中调用AddHub
,并收集任务列表
,然后在最后通过wait Task等待任务。当所有(任务)
时,返回值与私有异步任务RefreshHubs(对象)
的签名匹配ActivateAsync
调用RefreshHubs
,就像调用await RefreshHubs(null)
一样,最后调用await base.ActivateAsync()
匹配函数签名公共覆盖异步任务ActivateAsync()
//Sorry for the inconvenience of shorterned code, for context see the link "here (1)"...
override this.ActivateAsync() =
this.RegisterTimer(new Func<obj, Task>(this.FlushQueue), null, TimeSpan.FromMilliseconds(100.0), TimeSpan.FromMilliseconds(100.0)) |> ignore
if RoleEnvironment.IsAvailable then
this.RefreshHubs(null) |> Async.awaitPlainTask |> Async.RunSynchronously
else
this.AddHub("http://localhost:48777/") |> Async.awaitPlainTask |> Async.RunSynchronously
//Return value comes from here.
base.ActivateAsync()
member private this.RefreshHubs(_) =
//Code omitted, in case mor context is needed, take a look at the link "here (2)", sorry for the inconvinience...
//The return value is Task.
//In the C# version the AddHub provided tasks are collected and then the
//on the last line there is return await Task.WhenAll(newHubAdditionTasks)
newHubs |> Array.map(fun i -> this.AddHub(i)) |> Task.WhenAll
member private this.AddHub(address) =
//Code omitted, in case mor context is needed, take a look at the link "here (2)", sorry for the inconvinience...
//In the C# version:
//...
//hubs.Add(address, new Tuple<HubConnection, IHubProxy>(hubConnection, hub))
//}
//so this is "void" and could perhaps be Async<void> in F#...
//The return value is Task.
hubConnection.Start() |> Async.awaitTaskVoid |> Async.RunSynchronously
TaskDone.Done
您可以在FSharpx中使用
TaskBuilder
,并传入TaskScheduler.Current
。下面是我翻译RefreshHubs
的尝试。请注意,Task
用于代替Task
let RefreshHubs _ =
let task = TaskBuilder(scheduler = TaskScheduler.Current)
task {
let addresses =
RoleEnvironment.Roles.["GPSTracker.Web"].Instances
|> Seq.map (fun instance ->
let endpoint = instance.InstanceEndpoints.["InternalSignalR"]
sprintf "http://%O" endpoint.IPEndpoint
)
|> Seq.toList
let newHubs = addresses |> List.filter (not << hubs.ContainsKey)
let deadHubs = hubs.Keys |> Seq.filter (fun x ->
not (List.exists ((=) x) addresses))
// remove dead hubs
deadHubs |> Seq.iter (hubs.Remove >> ignore)
// add new hubs
let! _ = Task.WhenAll [| for hub in newHubs -> AddHub hub |]
return ()
}
让我们来看看=
让task=TaskBuilder(scheduler=TaskScheduler.Current)
任务{
让地址=
RoleEnvironment.Roles.[“GPSTracker.Web”].Instances
|>Seq.map(趣味实例->
让endpoint=instance.InstanceEndpoints。[“InternalSignaler”]
sprintf“http://%O”endpoint.IPEndpoint
)
|>序号:toList
让newHubs=addresses |>List.filter(而不是Seq.filter(fun x->
非(List.exists(=)x)地址)
//移除死毂
deadHubs |>Seq.iter(hubs.Remove>>忽略)
//添加新的集线器
let!=Task.WhenAll[|对于新集线器中的集线器->添加集线器集线器|]
返回()
}
我没有使用过奥尔良,但是如果它需要在自定义任务调度器上运行所有异步代码,那么用F#编码它将是一件令人头痛的事,因为异步
不支持这一点。您可以做到最好(AFAIK)将每个任务
转换为异步确实,这就是我试图做的,只是避免异步工作流。唉,我不确定我是否成功,无论如何,我对如何将某些C#模式转换为F#有点不确定(例如,我应该使用异步{}
,如果是,如何使用,或者如果不是,再次使用).通常我用这两种语言都写,我没有必要认真思考。我不知道如何评论这一部分,但我只是想指出我认为您的“here(2)”中原始C代码中存在的一些错误示例。Flush
需要是一个async Task
方法,而不是void
,因为HubConnection.Start
和IHupProxy.Invoke
都是返回Task
的异步方法,应该等待。您可能希望在通过foreach循环并执行任务时收集任务。在泛滥方法的d。我会考虑编写一个自定义生成器(一个用于<代码>异步的<代码> >),它直接与<代码>任务<代码>一起工作,而不是<代码>异步> <代码>,并使用当前<代码> TaskStalpder < /C> >继续运行。@ Svik:这是一个很好的建议,这是一个很好的尝试。(C#代码有点“哦,不”,包含了所有“void FunctionMutatesInternalState()”之类的东西。即使在C#和类中,传入参数、收集返回值并将其分配到某个位置也会让人感觉更容易。哦,这是一次很好的运行。谢谢!
type TaskBuilder(?continuationOptions, ?scheduler, ?cancellationToken) =
let contOptions = defaultArg continuationOptions TaskContinuationOptions.None
let scheduler = defaultArg scheduler TaskScheduler.Default
let cancellationToken = defaultArg cancellationToken CancellationToken.None
let RefreshHubs _ =
let task = TaskBuilder(scheduler = TaskScheduler.Current)
task {
let addresses =
RoleEnvironment.Roles.["GPSTracker.Web"].Instances
|> Seq.map (fun instance ->
let endpoint = instance.InstanceEndpoints.["InternalSignalR"]
sprintf "http://%O" endpoint.IPEndpoint
)
|> Seq.toList
let newHubs = addresses |> List.filter (not << hubs.ContainsKey)
let deadHubs = hubs.Keys |> Seq.filter (fun x ->
not (List.exists ((=) x) addresses))
// remove dead hubs
deadHubs |> Seq.iter (hubs.Remove >> ignore)
// add new hubs
let! _ = Task.WhenAll [| for hub in newHubs -> AddHub hub |]
return ()
}