我正在努力理解Async.[StartChild|Start]API 设计。我想要的是启动一个异步进程,该进程执行一些 tcp 流读取并根据到达 tcp 的命令调用回调。
由于这个异步过程并不真正返回任何单个值,看来我应该使用Async.Start. 在某些时候,我想“关闭”我的 tcp 客户端,并且“Async.Start 接受 CancellationToken”,这使我能够实现“关闭”。到目前为止一切顺利。
问题是,我想知道 tcp 客户端何时完成取消。一旦请求取消,就会完成一些缓冲区刷新工作,因此我不想在 tcp 客户端完成清理之前终止应用程序。但Async.Start返回单位,这意味着我无法知道这样的异步过程何时完成。所以,看起来Async.StartChild应该有帮助。我应该能够调用取消,并且当清理完成后,该异步将调用链中的下一个延续(或抛出异常?)。但是......Async.StartChild不采取CancellationToken,只采取超时。
为什么Async.StartChild只实现单个取消策略(超时)而不是公开更通用的方式(接受 CancellationToken)?
要回答问题的第一部分 - 如果您需要做一些清理工作,您可以将其放入finally,当工作流程取消时它将被调用。例如:
let work =
async {
try
printfn "first work"
do! Async.Sleep 1000
printfn "second work"
finally
printfn "cleanup" }
Run Code Online (Sandbox Code Playgroud)
假设您使用 运行此命令Async.Start,等待 500 毫秒,然后取消计算:
let cts = new System.Threading.CancellationTokenSource()
Async.Start(work, cts.Token)
System.Threading.Thread.Sleep(500)
cts.Cancel()
Run Code Online (Sandbox Code Playgroud)
输出将是“第一个工作,清理”。如您所见,取消计算将运行所有子句finally。
要回答问题的第二部分 - 如果您需要等到工作完成,您可以使用RunSynchronously(但是,如果您无论如何都阻塞的话,也许您实际上并不需要异步工作流程......)。
下面启动一个后台进程,500ms后取消主工作,然后同步启动主工作:
let cts = new System.Threading.CancellationTokenSource()
async {
do! Async.Sleep(500)
cts.Cancel() } |> Async.Start
try Async.RunSynchronously(work, cancellationToken=cts.Token)
with :? System.OperationCanceledException -> ()
printfn "completed"
Run Code Online (Sandbox Code Playgroud)
这将打印“第一项工作,清理,已完成” - 正如您所看到的,调用RunSynchronously被阻止,直到工作被取消。
| 归档时间: |
|
| 查看次数: |
187 次 |
| 最近记录: |