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" }
                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.
* Update on "real" async
What do I mean by "real" async? async is essentially a way to write "Here is some code, run that, if you encounter IO, go do something else and once the OS signals 'done' continue the remaining work." Now, as long as there is no IO (reading/writing from/to a file, stream, DB, waiting for a timer, ...) the current thread (in do!, Async.StartImmediate) will run the "prefix" code (potentially all code including inner do! async {). Once a "real" async operation is encountered, the "continuation" (the code after the IO operation) is scheduled and the former thread is free to do something else. Once the operation is completed the continuation is executed on the thread pool.
That is except for UI programs (WPF, WinForms, ...) where it is oftentimes desirable to run the continuation on the original thread (UI), because only that is allowed to write to the UI respectively shared data structures. In order to make that happen there needs to be a SynchronizationContext and some kind of event loop (the original thread needs to check whether there's work waiting).
In practice it is more complicated due to (amongst others) C# having 'hot' (already running) Tasks, F# cold (reusable) asyncs and both being used also for parallelism (CPU bound work distributed across multiple cores).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With