2

I was under the impression that let! in f# was smart enough to excute sequences of assignments in parallell. However, the following sample displays a different behavior, assignment of a,b,c seems to execute synchronously.

    let sleep sec =
        async
            {
                System.Threading.Thread.Sleep(sec * 1000)
                return sec
            }

    let bar = async 
                {
                    let! a = sleep 1
                    let! b = sleep 3
                    let! c = sleep 3
                    return a+b+c
                }

    let foo = Async.RunSynchronously(bar)
    printfn "%d" foo

Is that how it is/should be?

And if I want to execute a,b,c in parallell, am I supposed to use Async.Parallell ... |> Async.RunSynchronously ... then?

The above sample is ofcourse useless , the real usecase would be something like query a DB and call some webservices at the same time.

2 Answers 2

7

As Richard points out, asynchronous workflows are still fully sequential. I don't think that any projects attempting to do fully automatic parallelization have been fully successful, because doing that is just too difficult.

However, asynchronous workflows still make parallelization easier. The key thing is that they make it possible to do waiting without blocking threads (which is essential for scalability) and they also support automatic cancellation and easy exception handling to make your life easier. There are various patterns that allow you to parallelize code in asynchronous workflows.

  • Task-based you can start your three tasks in background and then wait until all of them complete (this is probably what you were expecting, so here is how to write that explicitly):

    let bar = async  { 
      let! atask = sleep 1 |> Async.StartChild
      let! btask = sleep 3 |> Async.StartChild
      let! ctask = sleep 3 |> Async.StartChild
      let! a = atask
      let! b = btask
      let! c = ctask
      return a + b + c } 
    
  • Data-parallel - if you have multiple workflows of the same type then you can create a workflow that runs all of them in parallel using Async.Parallel. When you then use let! it runs all three tasks and waits until they complete:

    let bar = async  { 
      let! all = Async.Parallel [ sleep 1; sleep 3; sleep 3 ]
      return all.[0] + all.[1] + all.[2] } 
    

Don Syme has an article discussing various patterns based on asynchronous workflows and you can find a comprehensive example in financial dashboard sample

Sign up to request clarification or add additional context in comments.

2 Comments

Async.StartAsChild should be Async.StartChild, I believe.
@wmeyer: Yes, you're right - thanks for the correction, I fixed the answer.
2

let!, in an async block (or more correctly "computation expression") executes the expression asynchronously but the block as a whole is still executed linearly. This is the benefit of async computation expressions: making a sequence of dependent asynchronous operations much easier to write by performing continuation passing for you.

(Other types of computation expression provide their own semantics for let!, yield!, etc.)

To perform parallel/concurrent execution you need multiple async expressions executed separately.

I was under the impression

You've misunderstood (quite understandably).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.