.net 'Async.StartImmediate'是否在'async'进程的整个生存期内在同一线程上运行该进程?

tquggr8v  于 2022-11-19  发布在  .NET
关注(0)|答案(2)|浏览(150)

这是对F#的Async.StartImmediate方法的引用。可能是一个转移,但这个方法的名称容易混淆,因为Async.Start * 也 * 立即启动async进程,只是在一个线程池上。
无论如何,文档中声明Async.StartImmediate使用调用线程启动进程。async进程在整个进程生命周期中是否继续在同一个线程上执行?或者它是否可能在某个时刻切换?据我所知,Async.Start允许进程切换底层线程,因为它运行在线程池之上。
编辑:为了澄清这个问题,我考虑一个不包含asynclet!do!return!等任何其他用法的async。例如:

async { printfn "testing" }
rur96b6h

rur96b6h1#

正如您已经发现的,不同之处在于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

其印刷了
异步前缀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限制的工作分布在多个内核上),因此它更加复杂。

6fe3ivhb

6fe3ivhb2#

我做了一个实验,似乎暗示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"

关于计算是否 * 停留 * 在线程上,我在 Expert F# 4.0 中找到了Async.StartImmediate
在当前线程上启动异步计算。它将在当前线程上运行,直到为该线程计划继续的第一个点;例如在原始异步I/O操作时。
它进一步说:
这将使用当前线程运行计算前缀来启动异步计算。例如,如果从GUI线程启动异步计算,则计算前缀将在GUI线程上运行。
我不完全确定“直到为线程调度延续的第一个点”或“计算的前缀”在了解async进程何时将从当前线程跳转方面的 * 确切 * 含义,但这是我能找到的最多信息。

相关问题