【发布时间】:2012-07-11 03:31:47
【问题描述】:
我正在使用 F# 做一些低级别的套接字工作,并且正在使一切异步。我有一个套接字,用于使用异步工作流来监听连接以处理它们,因此它使用它来包装 Socket.BeginListen() 和 Socket.EndListen()。
member socket.AsyncAccept () =
Async.FromBeginEnd( socket.BeginAccept, endOrDisposed socket.EndAccept null )
当我想停止监听时,此刻我正在对其执行 Socket.Close(),这将导致由 Socket.BeginAccept() 启动的异步操作完成。
最初我遇到了一个问题,因为无论 BeginXXX() 启动的操作如何完成,FromBeginEnd() 函数都会调用 EndXXX() 函数。在某些情况下,这会导致 EndXXX() 函数发生 ObjectDisposed 异常,因为在调用它时,Socket 已被关闭并释放。我添加了一个小处理函数,可以过滤掉这些异常:
let endOrDisposed endFunc defaultResult iar = try endFunc iar with | _ -> defaultResult
这可以解决问题,但在调试中运行时不行。我很清楚 Just My Code 选项可用于隐藏异常,但这可能会更频繁地发生在其他一些 IO 操作中,因此我也不想将处理器时间浪费在引发和捕获不应该的异常上一开始就真的在那里。此外,我可能不想隐藏在我确实需要调试的区域中引发其他异常的位置。
我查看了 Async.FromBeginEnd 的代码,无论如何它总是调用 EndXXX() 函数,我不确定这是最好的行为,也许我应该写一个替换它?或者有人对优雅的解决方案有任何其他想法吗?
我刚刚在文档中找到(当然我以前看过)这个:
要取消对 BeginAccept() 方法的挂起调用,请关闭 插座。当异步调用 Close() 方法时 操作正在进行中,提供给 BeginAccept() 的回调 方法被调用。随后调用 EndAccept() 方法将 抛出 ObjectDisposedException 以指示操作已 被取消了。
我仍然不喜欢这个例外,即使这是设计使然。我宁愿找到一种不在已处置对象上调用 EndXXX() 的方法。也许我可以在其中加入一些 CancellationToken 魔法?
【问题讨论】:
标签: asynchronous f# io