首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Async.StartImmediate对Async.RunSynchronously

Async.StartImmediate对Async.RunSynchronously
EN

Stack Overflow用户
提问于 2016-09-17 12:38:19
回答 1查看 2.3K关注 0票数 20

根据我有限的理解(甚至是错误的理解),Async.StartImmediate和Async.RunSynchronously都在当前线程上启动异步计算。那么这两个函数到底有什么区别呢?有人能帮忙解释一下吗?

更新:

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

Dax示例在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不是null时,这才能工作,这对于GUI线程来说总是如此。特别是,如果您使用StartImmediate在控制台应用程序中运行,您会发现Async.Sleep确实会转到ThreadPool,因为控制台应用程序中的主线程没有SynchronizationContext.Current。

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

EN

回答 1

Stack Overflow用户

发布于 2016-09-17 13:45:48

Async.RunSynchronously等待直到整个计算完成。因此,在需要从常规代码运行异步计算并等待结果时,可以使用此方法。很简单。

Async.StartImmediate确保计算在当前上下文中运行,但不会等到整个表达式完成后再运行。它最常见的用途(至少对我来说)是当您想要在GUI线程上异步地运行计算时。例如,如果您想以1秒的间隔在GUI线程上做三件事,您可以编写

代码语言:javascript
复制
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控件的更新都必须从同一个线程中完成,这很难手动协调;以上所述消除了很多痛苦)。

再举一个例子,在这里:

代码语言:javascript
复制
// 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可以。

票数 15
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39546905

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档