Asynchronous F#如何运行多个异步任务并等待第一次完成的结果?
有许多例子说明了如何在类似f#的环境中执行异步任务 但是我如何异步地只等待第一个结果呢Asynchronous F#如何运行多个异步任务并等待第一次完成的结果?,asynchronous,f#,Asynchronous,F#,有许多例子说明了如何在类似f#的环境中执行异步任务 但是我如何异步地只等待第一个结果呢 例如,如果我想运行一些并行查找任务,并且我想在获得第一个成功结果时进行更深入的搜索。(基本上相当于任务。当在C#world中出现任何时……我能想到的最简单的实现如下所示: open FSharp.Control let getOneOrOther () = let queue = BlockingQueueAgent(1) let async1 = async { d
例如,如果我想运行一些并行查找任务,并且我想在获得第一个成功结果时进行更深入的搜索。(基本上相当于
任务。当在C#world中出现任何
时……我能想到的最简单的实现如下所示:
open FSharp.Control
let getOneOrOther () =
let queue = BlockingQueueAgent(1)
let async1 = async {
do! Async.Sleep (System.Random().Next(1000, 2000))
do! queue.AsyncAdd(1) } |> Async.Start
let async2 = async {
do! Async.Sleep (System.Random().Next(1000, 2000))
do! queue.AsyncAdd(2) } |> Async.Start
queue.Get()
for i in 1..10 do
printfn "%d" <| getOneOrOther ()
Console.ReadLine () |> ignore
在以下代码段中可以找到通用解决方案:
Async.Choice
可以嵌入到任何异步工作流中,就像Async.Parallel
一样。可选的输出类型编码了这样一种可能性,即子计算可以在没有令人满意的结果的情况下完成。似乎这个解决方案足够简单,无阻塞,适合我的情况
let any (list: Async<'T>[])=
let tcs = new TaskCompletionSource<'T>()
list |> Array.map (fun wf->Async.Start (async{
let! res=wf
tcs.TrySetResult (res) |> ignore
}))
|> ignore
Async.AwaitTask tcs.Task
let async1 = async {
do! Async.Sleep (System.Random().Next(1000, 2000))
return 1 }
let async2 = async {
do! Async.Sleep (System.Random().Next(1000, 2000))
return 2 }
printfn "%d" <| ([|async1;async2|] |> any |> Async.RunSynchronously)
let any(列表:Async()
list |>Array.map(fun wf->Async.Start(Async{
让!res=wf
tcs.TrySetResult(res)|>忽略
}))
|>忽略
Async.AwaitTask tcs.Task
设async1=async{
do!Async.Sleep(System.Random().Next(10002000))
返回1}
设async2=async{
do!Async.Sleep(System.Random().Next(10002000))
返回2}
printfn“%d”any |>Async.RunSynchronously)
基于事件的另一个实现:
let Choice (asyncs: seq<Async<'T>>) : Async<'T> =
async {
let e = Event<'T>()
let cts = new System.Threading.CancellationTokenSource()
do Async.Start(
asyncs
|> Seq.map (fun a -> async { let! x = a in e.Trigger x })
|> Async.Parallel
|> Async.Ignore,
cts.Token)
let! result = Async.AwaitEvent e.Publish
cts.Cancel()
return result
}
let选择(异步:seq=
异步的{
设e=Event我会使用类似于:
let any asyncs =
async {
let t =
asyncs
|> Seq.map Async.StartAsTask
|> System.Threading.Tasks.Task.WhenAny
return t.Result.Result }
你是否希望其他任务被中止,或者只是让它们在后台进行?我不想中止它们,但可能在将来,我想将此方法扩展到WaitForAnysuccesfullandFaiFallFail。我在f#是新手。在scala world中,用未来和承诺来实现这一点非常简单。值得注意的是从F#4.5开始,这是作为Async.Choice
内置的。我很惊讶在Async中没有这样的东西。谢谢链接。这不是阻塞吗?如何将WhenAny
的结果管道化到Async.waittask
,使用let!t
,然后返回t.result
?@nphx:你能添加吗请将您的建议作为新答案或使用要点?
let Choice (asyncs: seq<Async<'T>>) : Async<'T> =
async {
let e = Event<'T>()
let cts = new System.Threading.CancellationTokenSource()
do Async.Start(
asyncs
|> Seq.map (fun a -> async { let! x = a in e.Trigger x })
|> Async.Parallel
|> Async.Ignore,
cts.Token)
let! result = Async.AwaitEvent e.Publish
cts.Cancel()
return result
}
let any asyncs =
async {
let t =
asyncs
|> Seq.map Async.StartAsTask
|> System.Threading.Tasks.Task.WhenAny
return t.Result.Result }