gpt4 book ai didi

f# - Async.StartImmediate vs Async.RunSynchronously

转载 作者:行者123 更新时间:2023-12-03 20:50:07 33 4
gpt4 key购买 nike

正如我有限(甚至错误)的理解,Async.StartImmediate 和 Async.RunSynchronously 在当前线程上启动异步计算。那么这两个功能究竟有什么区别呢?谁能帮忙解释一下?

更新:

https://github.com/fsharp/fsharp/blob/master/src/fsharp/FSharp.Core/control.fs 查看 F# 源代码后,我想我有点明白会发生什么。 Async.StartImmediate 在当前线程上启动异步。在它命中异步绑定(bind)之后,它是否会继续在当前线程上运行取决于异步绑定(bind)本身。例如,如果异步绑定(bind)调用 Async.SwitchToThreadPool,它将在 ThreadPool 而不是当前线程上运行。在这种情况下,如果您想返回当前线程,则需要调用 Async.SwitchToContext。否则,如果异步绑定(bind)没有做任何切换到其他线程,Async.StartImmediate 将继续在当前线程上执行异步绑定(bind)。在这种情况下,如果您只想停留在当前线程上,则无需调用 Async.SwitchToContext。

Dax Fohl 的示例在 GUI 线程上工作的原因是因为 Async.Sleep 仔细捕获
SynchronizationContext.Current 并确保继续在捕获的上下文中运行,使用
SynchronizationContext.Post()。见 https://github.com/fsharp/fsharp/blob/master/src/fsharp/FSharp.Core/control.fs#L1631 ,其中 unprotectedPrimitiveWithResync 包装器更改了“args.cont”(继续)
成为捕获上下文的 Post(参见:https://github.com/fsharp/fsharp/blob/master/src/fsharp/FSharp.Core/control.fs#L1008 — trampolineHolder.Post 基本上是 SynchronizationContext.Post)。这只会工作
当 SynchronizationContext.Current 不为空时,GUI 线程总是如此。尤其,
如果你在控制台应用中使用 StartImmediate 运行,你会发现 Async.Sleep 确实会进入 ThreadPool,因为控制台应用中的主线程没有 SynchronizationContext.Current。

总而言之,这确实适用于 GUI 线程,因为某些函数(如 Async.Sleep、Async.AwaitWaitHandle 等)会仔细捕获并确保回发到先前的上下文。
看起来这是一种故意的行为,但是这似乎没有在 MSDN 中的任何地方记录。

最佳答案

Async.RunSynchronously等到整个计算完成。因此,当您需要从常规代码运行异步计算并需要等待结果时,请使用它。很简单。
Async.StartImmediate确保计算在当前上下文中运行,但不会等到整个表达式完成。最常见的用途(至少对我而言)是当您想在 GUI 线程上异步运行计算时。例如,如果你想以 1 秒的间隔在 GUI 线程上做三件事,你可以写

async {
do! Async.Sleep 1000
doThing1()
do! Async.Sleep 1000
doThing2()
do! Async.Sleep 1000
doThing3()
} |> Async.StartImmediate

这将确保在 GUI 线程中调用所有内容(假设您从 GUI 线程调用它),但不会在整个 3 秒内阻塞 GUI 线程。如果您使用 RunSynchronously在那里,它会在一段时间内阻塞 GUI 线程,并且您的屏幕将变得无响应。

(如果您还没有进行过 GUI 编程,那么请注意,对 GUI 控件的更新都必须从同一个线程中完成,这可能难以手动协调;以上内容消除了很多痛苦)。

再举一个例子,这里:
// Async.StartImmediate
async {
printfn "Running"
do! Async.Sleep 1000
printfn "Finished"
} |> Async.StartImmediate
printfn "Next"

> Running
> Next
// 1 sec later
> Finished

// Async.RunSynchronously
async {
printfn "Running"
do! Async.Sleep 1000
printfn "Finished"
} |> Async.RunSynchronously
printfn "Next"

> Running
// 1 sec later
> Finished
> Next

// Async.Start just for completion:
async {
printfn "Running"
do! Async.Sleep 1000
printfn "Finished"
} |> Async.Start
printfn "Next"

> Next
> Running // With possible race condition since they're two different threads.
// 1 sec later
> Finished

另请注意 Async.StartImmediate不能返回值(因为在继续之前它没有运行完成),而 RunSynchronously能够。

关于f# - Async.StartImmediate vs Async.RunSynchronously,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39546905/

33 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com