【发布时间】:2014-11-19 16:08:38
【问题描述】:
我对如何在 C# 中使用 TPL 完成异步取消感到非常满意,但在 F# 中我有点困惑。显然通过调用Async.CancelDefaultToken() 足以取消传出的Async<'T> 操作。但它们并没有像我预期的那样被取消,它们只是......消失了......我无法正确检测到取消并正确拆除堆栈。
例如,我的这段代码依赖于使用 TPL 的 C# 库:
type WebSocketListener with
member x.AsyncAcceptWebSocket = async {
let! client = Async.AwaitTask <| x.AcceptWebSocketAsync Async.DefaultCancellationToken
if(not(isNull client)) then
return Some client
else
return None
}
let rec AsyncAcceptClients(listener : WebSocketListener) =
async {
let! result = listener.AsyncAcceptWebSocket
match result with
| None -> printf "Stop accepting clients.\n"
| Some client ->
Async.Start <| AsyncAcceptMessages client
do! AsyncAcceptClients listener
}
当传递给x.AcceptWebSocketAsync的CancellationToken被取消时,返回null,然后AsyncAcceptWebSocket方法返回None。我可以用断点验证这一点。
但是,AsyncAcceptClients(调用者)永远不会得到 None 的值,方法就结束了,"Stop accepting clients.\n" 永远不会显示在控制台上。如果我将所有内容都包装在 try\finally 中:
let rec AsyncAcceptClients(listener : WebSocketListener) =
async {
try
let! result = listener.AsyncAcceptWebSocket
match result with
| None -> printf "Stop accepting clients.\n"
| Some client ->
Async.Start <| AsyncAcceptMessages client
do! AsyncAcceptClients listener
finally
printf "This message is actually printed"
}
然后当listener.AsyncAcceptWebSocket 返回None 时,我在finally 中输入的内容将被执行,但我在match 中的代码仍然没有。 (实际上,它会为每个连接的客户端在 finally 块上打印一次消息,所以也许我应该转向迭代方法?)
但是,如果我使用自定义 CancellationToken 而不是 Async.DefaultCancellationToken,一切都会按预期进行,并且 "Stop accepting clients.\n" 消息会打印在屏幕上。
这是怎么回事?
【问题讨论】:
标签: f# f#-3.0 cancellation f#-async