我正在尝试在名为listControls的函数之上编写一个Async包装器,该函数从根控件开始提取Forms控件列表。计划是根据Control.BeginInvoke,Control.EndInvoke和Async.FromBeginEnd实现它
代码如下:
type private ListControls = delegate of unit -> Control list
let asyncListControls (root:Forms.Control) : Async<Control list> =
let beginInvoke (_, _) =
new ListControls(fun () -> listControls root)
|> root.BeginInvoke
let endInvoke result =
root.EndInvoke result :?> Control list
Async.FromBeginEnd (beginInvoke, endInvoke)
我得到的行为是永远不会执行 endInvoke 。谁知道我做错了什么?有更好的方法吗?
修改的
为了说清楚,最终使用Async.RunSynchronously执行此计算。
此外,如果我用
替换此代码/// code below is reproduced from memory and might not compile
let asyncListControls (root:Forms.Control) : Async<Control list> =
let ctx = WindowsFormsSynchronizationContext.Current
async {
do! Async.SwitchToContext ctx
return listControls root
do! Async.SwitchToThreadPool ()
}
...然后它似乎工作,但我不喜欢它,因为强制上下文切换和异步计算应该在UI线程上构建的事实
答案 0 :(得分:1)
Async
与Task
不同,因为它不会在创作时开始。正如Daniel指出的那样,您必须使用Async
或其他方法明确启动Async.RunSynchronously
。
答案 1 :(得分:0)
我对以下问题的不满:
在UI线程上使用Async.RunSynchronously执行异步操作,这会阻塞线程。
在执行期间,与Control.BeginInvoke一样,它将消息发送到UI线程。无法处理此消息,因为UI线程在Async.RunSynchron上被阻塞,从而导致死锁。