TalBeno
TalBeno

Reputation: 289

F# async ; Run asynch expression in same thread, and yet be able to wait on async operations (e.g. do!)

Experimenting some with F# async taught me that I can StartImmediate on the current running thread. This allows me, it seems, to run an async expression which can still pass out control, whenever getting inside of it to some async operation (e.g. do!), to the code outside of the async expression. Please see the simple example below:

open System.Threading

let workThenWait() = async { 
  printfn "async start"
  do! Async.Sleep(1000) 
  printfn "async end"
  }

let demo() = 
  workThenWait() |> Async.StartImmediate
  printfn "main started"
  // here I want to wait to the async expression in case it has passed control
  printfn "main end"

demo()

The result we get is:

async start
main started
main end
async end

On the other hand, if I execute the same async expression (in this case workThenWait) using StartAsTask (inside demo), I can potentially wait on it at the end.

MY QUESTION is:

using the previous example using StartImmediate, can I run on the same thread, but ALSO wait at the end for the async expression in case some async operation (such as do!) is called and passes control forward?

Upvotes: 3

Views: 529

Answers (2)

Arbil
Arbil

Reputation: 989

You can do this with Hopac libary:

let workThenWait() = job { 
  printfn "async start"
  do! Hopac.Timer.Global.sleep (TimeSpan.FromMilliseconds 1000.) 
  printfn "async end"
  }

let demo() = 
  let promise = workThenWait() |> Promise.start |> run
  printfn "main started"
  // here I want to wait to the async expression in case it has passed control
  let result = run promise
  printfn "main end"

demo()

Hopac is both more performant and functional than async and is little known compared to how good it is. I highly recommend it.

Upvotes: 1

Grzegorz Sławecki
Grzegorz Sławecki

Reputation: 1797

I think You need Async.RunSynchronously (http://msdn.microsoft.com/en-us/library/ee370262.aspx)

update: Ok, now I understand better what You want, and I was able to achieve this with Async.StartWithContinuations method.

Here's the code:

open System.Threading
let f() =
printfn "main thread: %A" Thread.CurrentThread.ManagedThreadId
let c1 = 
    async {
            printfn "c1 async thread: %A" Thread.CurrentThread.ManagedThreadId
            do! Async.Sleep(1000) 
            return "some result"
          }

let continuation s = 
    printfn "continuation thread: %A" Thread.CurrentThread.ManagedThreadId
    printfn "now the code You want after waiting and the result %s" s

Async.StartWithContinuations( 
    c1, 
    continuation,
    (fun _ -> ()), 
    (fun _ -> ())
    )

printfn "Code that runs during async computation"

Now this is definitely not very readable as the flow of the code is not obvious. I couldn't find any better solution.

Upvotes: 2

Related Questions