我很难理解Async.[StartChild|Start]
API设计。
我想要的是启动一个异步进程,它根据到达tcp的命令执行一些tcp流读取和调用回调。
由于这个异步进程并没有真正返回任何单个值,所以我似乎应该使用Async.Start
。在某些时候我想“关闭”我的tcp客户端和`Async.Start采取CancellationToken,这使我能够实现'关闭'。到目前为止一直很好。
问题是,我想知道tcp客户端何时完成取消。有一些缓冲区刷新工作完成,一旦请求取消,所以我不想在tcp客户端完成清理之前终止应用程序。但是Async.Start
返回单位,这意味着我无法知道这种异步过程何时完成。所以,Async.StartChild
看起来应该有所帮助。我应该能够调用取消,当清理完成后,这个异步将调用链中的下一个contiuation(或抛出异常?)。但是...... Async.StartChild
不会取消取消,只会超时。
为什么Async.StartChild
只实现单一取消策略(超时)而不是暴露更通用的方式(接受CancellationToken)?
答案 0 :(得分:4)
要回答问题的第一部分 - 如果您需要进行一些清理工作,可以将其放在finally
中,并在取消工作流时调用它。例如:
let work =
async {
try
printfn "first work"
do! Async.Sleep 1000
printfn "second work"
finally
printfn "cleanup" }
假设您使用Async.Start
运行此命令,等待500毫秒然后取消计算:
let cts = new System.Threading.CancellationTokenSource()
Async.Start(work, cts.Token)
System.Threading.Thread.Sleep(500)
cts.Cancel()
输出将是“首次工作,清理”。如您所见,取消计算将运行所有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"
这打印出“第一次工作,清理,完成” - 正如您所看到的,RunSynchronously
来电被阻止,直到工作被取消。