clagccs
clagccs

Reputation: 2324

custom async primitive function in f# using Async.FromContinuations

I'm a bit newbie with the async workflow and I think it has somethings I am not understand so well...I'm following the book Real world functional programming and in it writes the async primitive in this way

let Sleep(time) =
  Async.FromContinuations(fun (cont, econt, ccont) ->
     let tmr = new System.Timers.Timer(time, AutoReset = false)
     tmr.Elapsed.Add(fun _ -> cont())
    tmr.Start()
  );;

I've tried write my own async primitive using a very slow factorial implementation, the code is it:

let rec factorial(n : int) (mem : bigint) =
   match n with
   | 0 | 1 -> printfn "%A" mem
   | _ ->  factorial (n - 1) (mem * bigint(n))


let BigFactorial(numero,mesaje)=
    Async.FromContinuations(fun (cont,error,cancelation) ->
                                printfn "begin number: %s" mesaje
                                factorial numero 1I |>ignore
                                printfn "End number: %s ." mesaje
                                cont())

now I wrote this

 Async.RunSynchronously(async{
     printfn "Start!!..."
     do! BigFactorial(30000,"30M")
     do! BigFactorial(10000, "10M")
     printfn "End!!..."
 })

but it isn't running in async way precisely....

Start!!...
begin number: 30M
2759537246219...(A nice long number!)
end number: 30M .
begin number: 10M .
2846259680917054518906...(other nice number)
End!!...

if I execute it in parallel then works good...

let task1 = async{
   printfn "begin"
   do! BigFactorial(30000,"30")
   printfn "end..." 
}

let task2 = async{
   printfn "begin"
   do! BigFactorial(10000,"10")
   printfn "end!!..." 
}


Async.RunSynchronously(Async.Parallel[task1;task2])

begin
begin: 30 
begin
begin: 10M

//long numbers here

end....
end.....

but I wish know the reason (or the several reasons!) why the first code doesn't work... thanks so much I appreciate any help...

Upvotes: 0

Views: 333

Answers (1)

ildjarn
ildjarn

Reputation: 62975

As with all async bindings, do! runs on the current thread, and thus your two sequential do!s run sequentially.

If you want them to run in parallel, you must say so explicitly:

async {
   printfn "Start!!..."
   let! tokenA = BigFactorial (30000, "30M") |> Async.StartChild // on new thread
   let! tokenB = BigFactorial (10000, "10M") |> Async.StartChild // on new thread
   do! tokenA // block until `BigFactorial (30000, "30M")` finishes
   do! tokenB // block until `BigFactorial (10000, "10M")` finishes
   printfn "End!!..." }
|> Async.RunSynchronously

Upvotes: 2

Related Questions