This is in reference to F#'s Async.StartImmediate
method. Possibly a diversion, but this method is confusingly named because Async.Start
also starts the async
process immediately, just on a thread pool.
Anyway, the documentation states that Async.StartImmediate
starts the process using the calling thread. Does the async
process continue to execute on that same thread throughout the lifetime of the process? Or is it possible it switches at some point? To my knowledge, Async.Start
allows the process to switch underlying threads since it runs on top of a thread pool.
Edit: To clarify the question, I am thinking about an async
that doesn't contain any other usage of async
, let!
, do!
, return!
, etc. for example:
async { printfn "testing" }
CodePudding user response:
I did an experiment that seems to imply that Async.StartImmediate
does indeed propagate down to contained async
processes.
// 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
Then running this:
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"
Regarding if the computation stays on the thread, I found this in Expert F# 4.0 for Async.StartImmediate
:
Starts the async computation on the current thread. It will run on the current thread until the first point where a continuation is scheduled for the thread; for example, at a primitive asynchronous I/O operation.
It further says:
This starts an async computation using the current thread to run the prefix of the computation. For example, if you start an async computation from a GUI thread, the prefix of the computation will run on the GUI thread.
I am not entirely sure what exactly "until the first point where a continuation is scheduled for the thread" or "the prefix of the computation" mean in terms of knowing when the async
process will jump from the current thread, but this is the most information I could find.
CodePudding user response:
As you already found, the difference is that StartImmediate
runs the prefix on the current thread while Start
switches immediately. To get an actual continuation, you need a real async operation, e.g. Async.Sleep
. async { }
by itself is not async but lets you use async. That is, the difference is visible with
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
which prints
async prefix StartImmediate: Main
async prefix Start: .NET ThreadPool Worker
async continuation StartImmediate: .NET ThreadPool Worker
async continuation Start: .NET ThreadPool Worker
Note that the two operations are interleaved now and the continuation is run on the thread pool in both cases.