"Async.StartImmediate"是否在进程的整个生命周期内在同一线程上运行"A



这是对F#的Async.StartImmediate方法的引用。可能是一种转移,但这种方法的名称令人困惑,因为Async.Start立即启动async进程,只是在线程池上。

无论如何,文档说明Async.StartImmediate使用调用线程启动进程。在进程的整个生命周期中,async进程是否继续在同一线程上执行?或者它可能在某个时刻切换?据我所知,Async.Start允许进程切换底层线程,因为它运行在线程池的顶部。

编辑:为了澄清这个问题,我想的是一个async,它不包含asynclet!do!return!等的任何其他用法。例如:

async { printfn "testing" }

正如您已经发现的,不同之处在于StartImmediate在当前线程上运行前缀,而Start则立即切换。要获得实际的延续,您需要一个";真实的"*异步操作,例如Async.Sleepasync { }本身不是异步,而是允许使用异步。也就是说,的差异是显而易见的

open System.Threading
Thread.CurrentThread.Name <- "Main"
let computation s = async {
printfn "async prefix %s: %s" s Thread.CurrentThread.Name
do! Async.Sleep 1
printfn "async continuation %s: %s" s Thread.CurrentThread.Name
}
computation "StartImmediate" |> Async.StartImmediate
computation "Start" |> Async.Start

它打印

异步前缀StartImmediat:Main
异步前缀开始:.NET线程池工作程序
同步延续StartImmediate:.NET线程库工作程序
异步延续开始:.NET ThreadPool工作程序

请注意,现在这两个操作是交错的,在这两种情况下,延续都在线程池上运行。

*更新";真实的";异步

我所说的";真实的";异步?CCD_ 16本质上是一种写";这里有一些代码,如果你遇到IO,运行它,去做其他事情,一旦操作系统发出"完成"的信号,就继续剩下的工作"现在,只要没有IO(从文件、流、DB读取/写入,等待计时器,…(,当前线程(在do!Async.StartImmediate中(将运行";前缀";代码(可能包括内部do! async {的所有代码(。曾经;真实的";如果遇到异步操作;"延续";(IO操作之后的代码(被调度,并且前一个线程可以自由地做其他事情。一旦操作完成,就在线程池上执行延续。

这是除了UI程序(WPF、WinForms…(,在这些程序中,通常希望在原始线程(UI(上运行延续,因为只有它才被允许分别写入UI共享的数据结构。为了实现这一点,需要有一个SynchronizationContext和某种事件循环(原始线程需要检查是否有工作在等待(。

在实践中,它更复杂,因为(除其他外(C#具有"热"(已运行(Tasks和F#冷(可重复使用(asyncs,并且两者都用于并行性(分布在多个核上的CPU绑定工作(。

我做了一个实验,似乎暗示Async.StartImmediate确实向下传播到包含的async进程。

// async.fsx
let outerAsync = async {
printfn "Outer async thread: %A" System.Threading.Thread.CurrentThread.Name
do! async {
printfn "Inner async thread: %A" System.Threading.Thread.CurrentThread.Name
}
}
System.Threading.Thread.CurrentThread.Name <- "main thread"
printfn "Main thread: %A" System.Threading.Thread.CurrentThread.Name
printfn "Async.StartImmediate"
Async.StartImmediate outerAsync
printfn "Async.Start"
Async.Start outerAsync

然后运行这个:

PS > dotnet fsi .async.fsx
Main thread: "main thread"
Async.StartImmediate
Outer async thread: "main thread"
Inner async thread: "main thread"
Async.Start
Outer async thread: ".NET ThreadPool Worker"
Inner async thread: ".NET ThreadPool Worker"

关于计算是否保持在线程上,我在Async.StartImmediate:的Expert F#4.0中发现了这一点

在当前线程上启动异步计算。它将在当前线程上运行,直到为线程调度延续的第一个点;例如在基元异步I/O操作处。

它进一步说:

这将使用当前线程启动异步计算,以运行计算的前缀。例如,如果从GUI线程启动异步计算,则计算的前缀将在GUI线程上运行。

我不完全确定到底是什么"直到为线程"调度继续的第一点;或";计算的前缀";意思是知道async进程何时会从当前线程跳出来,但这是我能找到的最多的信息。

相关内容

最新更新