这是对F#的Async.StartImmediate
方法的引用。可能是一个转移,但这个方法的名称容易混淆,因为Async.Start
* 也 * 立即启动async
进程,只是在一个线程池上。
无论如何,文档中声明Async.StartImmediate
使用调用线程启动进程。async
进程在整个进程生命周期中是否继续在同一个线程上执行?或者它是否可能在某个时刻切换?据我所知,Async.Start
允许进程切换底层线程,因为它运行在线程池之上。
编辑:为了澄清这个问题,我考虑一个不包含async
、let!
、do!
、return!
等任何其他用法的async
。例如:
async { printfn "testing" }
2条答案
按热度按时间rur96b6h1#
正如您已经发现的,不同之处在于
StartImmediate
在当前线程上运行 * 前缀 ,而Start
立即切换。要获得真正的延续,您需要一个“真实的的” 异步操作,例如Async.Sleep
。async { }
本身 * 不是 * 异步,但允许您 * 使用 * 异步。也就是说,使用其印刷了
异步前缀StartImmediate:主菜单
异步前缀开始:.NET线程池工作线程
异步继续立即开始:.NET线程池工作线程
异步继续开始:.NET线程池工作线程
请注意,这两个操作现在是交叉执行的,在这两种情况下,continuation都在线程池上运行。
*“真实的”异步更新
我所说的“真实的的”异步是什么意思?
async
* 本质上 * 是这样写的:“这里有一些代码,运行它,如果遇到IO,就去做其他事情,一旦操作系统发出”完成“信号,就继续剩余的工作。”现在,只要没有IO(阅读/写入文件、流、DB、等待计时器等)当前线程(在do!
、Async.StartImmediate
中)将运行“前缀”代码一旦遇到“真实的的”异步操作,“继续”(IO操作之后的代码)被调度,前一个线程可以自由地做其他事情。一旦操作完成,继续在线程池中执行。除了UI程序(WPF,WinForms,......),在这些程序中,通常需要在原始线程(UI)上运行continuation,因为只有它才允许写入UI各自的共享数据结构。为了实现这一点,需要有一个
SynchronizationContext
和某种类型的事件循环(原始线程需要检查是否有工作等待)。在实践中,由于(除其他外)C#具有“热”(已运行)
Task
s,F#具有“冷”(可重用)async
s,并且两者都用于并行(CPU限制的工作分布在多个内核上),因此它更加复杂。6fe3ivhb2#
我做了一个实验,似乎暗示
Async.StartImmediate
确实向下传播到包含的async
进程。然后运行以下命令:
关于计算是否 * 停留 * 在线程上,我在 Expert F# 4.0 中找到了
Async.StartImmediate
:在当前线程上启动异步计算。它将在当前线程上运行,直到为该线程计划继续的第一个点;例如在原始异步I/O操作时。
它进一步说:
这将使用当前线程运行计算前缀来启动异步计算。例如,如果从GUI线程启动异步计算,则计算前缀将在GUI线程上运行。
我不完全确定“直到为线程调度延续的第一个点”或“计算的前缀”在了解
async
进程何时将从当前线程跳转方面的 * 确切 * 含义,但这是我能找到的最多信息。