Sam
Sam

Reputation: 2865

Why the need for usage of "do! Async" style functions within F# Async Workflows?

I am new to F# Async workflows. Generally code and examples introducing this topic contain examples like the following (simplified):

let sleepWorkflow = 
    async{
        printfn "Starting sleep workflow at %O" DateTime.Now.TimeOfDay
        do! Async.Sleep 2000
        printfn "Finished sleep workflow at %O" DateTime.Now.TimeOfDay
    }

Async.RunSynchronously sleepWorkflow

I am trying to understand the need for do! Async.Sleep 2000 as opposed to do Threading.Thread.Sleep(2000) in its place.

From my understanding, BOTH approaches will run the code synchronously at that point.

What is the difference (I assume there must be) and when should one be using one approach versus the other?

Upvotes: 2

Views: 289

Answers (1)

Tomas Petricek
Tomas Petricek

Reputation: 243051

The difference is that using Thread.Sleep blocks the current thread so that it cannot do anything else while Async.Sleep creates a system timer, releases the current thread (so that it can do other things) and then (after the time elapses) acquires a thread again and runs the rest of the code.

This matters if you have a large number of async workflows that run in parallel (because having a dedicated thread for each would be expensive) or when you are running code on the GUI thread (there is just one thread and you should not block it).

To better understand this, you can change the number of thread pool threads to 1 and try the following code using both synchronous and asynchronous blocking:

System.Threading.ThreadPool.SetMinThreads(1, 1)
System.Threading.ThreadPool.SetMaxThreads(1, 1)

for i in 1 .. 5 do
  async { System.Threading.Thread.Sleep(1000)
          printfn "Done" } |> Async.Start

for i in 1 .. 5 do
  async { do! Async.Sleep(1000)
          printfn "Done" } |> Async.Start

After running the first for loop, you'll the "Done" messages will be printed with 1 second delays (because the one thread is repeatedly blocked for 1 second).

After running the second for loop, you'll see "Done" messages printed all at once after 1 second. This is because the asynchronous waiting is not actually blocking the thread and so the 5 timers will all elapse and then use the 1 available thread to do the printing (which takes almost no time).

Upvotes: 8

Related Questions