Async.fromBeginEnd 使用 WinForms Begin/EndInvoke
Async.fromBeginEnd with WinForms Begin/EndInvoke
我正在尝试在名为 listControls 的函数之上编写异步包装器,该函数从根控件开始提取表单控件列表。计划是按照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 线程
Async
与 Task
的不同之处在于它不会在创建时开始。正如 Daniel 指出的那样,您必须使用 Async.RunSynchronously
或其他方法明确启动 Async
。
我对问题的理解如下:
异步操作是在 UI 线程上用 Async.RunSynchronously 执行的,它正在阻塞线程。
在执行过程中,与 Control.BeginInvoke 一样,它向 UI 线程发送消息。无法处理此消息,因为 UI 线程在 Async.RunSynchronously 上被阻塞,因此出现死锁。
我正在尝试在名为 listControls 的函数之上编写异步包装器,该函数从根控件开始提取表单控件列表。计划是按照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 线程
Async
与 Task
的不同之处在于它不会在创建时开始。正如 Daniel 指出的那样,您必须使用 Async.RunSynchronously
或其他方法明确启动 Async
。
我对问题的理解如下:
异步操作是在 UI 线程上用 Async.RunSynchronously 执行的,它正在阻塞线程。
在执行过程中,与 Control.BeginInvoke 一样,它向 UI 线程发送消息。无法处理此消息,因为 UI 线程在 Async.RunSynchronously 上被阻塞,因此出现死锁。