我必须通过网络多次调用 API。
let RestCall1 args = async{ Thread.Sleep (1000); return args}
let RestCall2 args = async{Thread.Sleep (1000); return args}
我知道 async{...} 上下文会影响性能,因此我尝试最大程度地减少创建的上下文数量。另外,管道化也很尴尬。
let nested4 args = async{ let! x = RestCall1 args; return args }
let nested7 args = async{ let! x = RestCall2 args; return args }
let outerAsync (args : string) =
async {
let args1 = args
|> nested1
|> nested2
|> nested3
let! args2 = nested4 args1
let args3 = args2
|> nested5
|> nested6
return nested7 args3
}
有没有办法在不使用 RunSynch 阻塞线程的情况下执行此操作(如下面的示例)?
let nested4 args = RestCall1 args |> Async.RunSynchronously
let nested7 args = RestCall2 args |> Async.RunSynchronously
let outerAsync (args : string) =
async {
return
args
|> nested1
|> nested2
|> nested3
|> nested4
|> nested5
|> nested6
|> nested7
}
最佳答案
您想要避免 Async.Runsynchronously 是正确的,这会阻塞(请参阅 "Does Async.RunSynchronously block?" )。
正如 TheQuickBrownFox 所建议的,您需要一个提供 Async.map 和 Async.bind 的库。这里我使用了FsToolkit.ErrorHandling:
open System.Threading
open FsToolkit.ErrorHandling
let restCall1 args = async{ Thread.Sleep (1000); return args }
let restCall2 args = async{ Thread.Sleep (1000); return args }
let nested1 args = args
let nested2 args = args
let nested3 args = args
let nested4 args = restCall1 args
let nested5 args = args
let nested6 args = args
let nested7 args = restCall2 args
let outerAsync (args : string) : Async<string> =
args
|> nested1
|> nested2
|> nested3
|> nested4
|> Async.map nested5
|> Async.map nested6
|> Async.bind nested7
Async.map 采用nested5 并将其签名从 (string -> string)
更改为至(Async<string> -> Async<string>)
。它被称为 functor .
Async.bind 采用nested7 并将其签名从 (string -> Async<string>)
更改为至(Async<string> -> Async<string>)
.
关于async-await - F# 中的嵌套异步上下文,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64811512/