Execute Code on Main Thread from Async F#

Execute Code on Main Thread from Async F#

You may try this to go back to main thread:

InvokeOnMainThread(fun _ -> ... ) 

But I think when you get data from the completionHandler, it has been on the main thread.

Post messages from async threads to main thread in F#

I ended up creating an EventSink that has a queue of callbacks that are executed on the main PowerShell thread via Drain(). I put the main computation on another thread. The pull request has the full code and more details.

Sample Image

Sample Image

F# Making the result of an async workflow available to be displayed by the UI thread

Here's my code, I've removed the Console.Writeline() calls, you would just replace those with logger calls (or Debug.WriteLine(), or whatever).

open System
open System.Threading
open System.Windows

let createWindow() =
let window = Window()
window.Title <- "MyWindow"
window.Show()
window

let runWindowWithUser (window: Window) user =
window.Title <- (user + "'s Window")

let loginTask =
async {
Thread.Sleep(1000)
let user = "MyUser"
return user
}

[<EntryPoint; STAThread>]
let main _ =
let app = Application()
app.MainWindow <- createWindow()

app.Startup.Add (fun _ ->
async {
let context = SynchronizationContext.Current
do! Async.SwitchToThreadPool()
let! user = loginTask
do! Async.SwitchToContext context
runWindowWithUser app.MainWindow user
} |> Async.StartImmediate
)

app.Run()

How does F#'s async really work?

A few things.

First, the difference between

let resp = req.GetResponse()

and

let! resp = req.AsyncGetReponse()

is that for the probably hundreds of milliseconds (an eternity to the CPU) where the web request is 'at sea', the former is using one thread (blocked on I/O), whereas the latter is using zero threads. This is the most common 'win' for async: you can write non-blocking I/O that doesn't waste any threads waiting for hard disks to spin around or network requests to return. (Unlike most other languages, you aren't forced to do inversion of control and factor things into callbacks.)

Second, Async.StartImmediate will start an async on the current thread. A typical use is with a GUI, you have some GUI app that wants to e.g. update the UI (e.g. to say "loading..." somewhere), and then do some background work (load something off disk or whatever), and then return to the foreground UI thread to update the UI when completed ("done!"). StartImmediate enables an async to update the UI at the start of the operation and to capture the SynchronizationContext so that at the end of the operation is can return to the GUI to do a final update of the UI.

Next, Async.RunSynchronously is rarely used (one thesis is that you call it at most once in any app). In the limit, if you wrote your entire program async, then in the "main" method you would call RunSynchronously to run the program and wait for the result (e.g. to print out the result in a console app). This does block a thread, so it is typically only useful at the very 'top' of the async portion of your program, on the boundary back with synch stuff. (The more advanced user may prefer StartWithContinuations - RunSynchronously is kinda the "easy hack" to get from async back to sync.)

Finally, Async.Parallel does fork-join parallelism. You could write a similar function that just takes functions rather than asyncs (like stuff in the TPL), but the typical sweet spot in F# is parallel I/O-bound computations, which are already async objects, so this is the most commonly useful signature. (For CPU-bound parallelism, you could use asyncs, but you could also use TPL just as well.)

Consuming F# Async from C#

This Works exactly as I want (unlike the question this version returns an int as well which is plus):

type public Class1() = 
let printThread (message) = printfn "%s %A" message Thread.CurrentThread.ManagedThreadId

let bar =
printThread ("first bar")
async {
printThread ("first async")
do! Async.Sleep(1000)
printThread "last async"
return 1232
}

member this.convertToTask<'T> (asyn : Async<'T>) =
let tcs1 = new TaskCompletionSource<'T>()
let t1 = tcs1.Task
Async.StartWithContinuations
(
asyn
, (fun (k) -> tcs1.SetResult(k)), (fun exn -> tcs1.SetException(exn)), fun exn -> ())
t1

member this.X() : Task<int> = (bar |> this.convertToTask)

Using a F# event and asynchronous in multi-threaded code

FYI; the implementation for Event<int> can be found here.

The interesting bit seems to be:

member e.AddHandler(d) =
x.multicast <- (System.Delegate.Combine(x.multicast, d) :?> Handler<'T>)
member e.RemoveHandler(d) =
x.multicast <- (System.Delegate.Remove(x.multicast, d) :?> Handler<'T>)

Subscribing to an event combines the current event handler with the event handler passed into subscribe. This combined event handler replaces the current one.

The problem from a concurrency perspective is that here we have a race-condition in that concurrent subscribers might use the came current event handler to combine with and the "last" one that writes back the handler win (last is a difficult concept in concurrency these days but nvm).

What could be done here is to introduce a CAS loop using Interlocked.CompareAndExchange but that adds performance overhead that hurts non-concurrent users. It's something one could make a PR off though and see if it viewed favourably by the F# community.

WRT to your second question on what to do about it I can just say what I would do. I would go for the option of creating a version of FSharpEvent that supports protected subscribe/unsubscribe. Perhaps base it of FSharpEvent if your company FOSS policy allows it. If it turns out a success then it could form a future PR to F# core libary.

I don't know your requirements but it's also possible that if what you need is coroutines (ie Async) and not threads then it's possible to rewrite the program to use only 1 thread and thus you won't be affected by this race condition.

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

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.

How does Async.AwaitTask work in f#?

The point of wrapping a Task inside an Async is to more easily compose it with other asyncs, or to use it with let! from inside an async { ... } block. And in the latter case, the wrapped Task won't be started until its enclosing async { ... } block is started.

For example, let's look at the following function:

let printTask str =
async {
printfn "%s" str
} |> Async.StartAsTask

This doesn't do much; its only reason for existence is so that you can tell when it has started running, because it will print a message to the screen. If you call it from F# Interactive:

printTask "Hello"

You'll see the following output:

Hello
val it : Threading.Tasks.Task<unit> =
System.Threading.Tasks.Task`1[Microsoft.FSharp.Core.Unit]
{AsyncState = null;
CreationOptions = None;
Exception = null;
Id = 4;
IsCanceled = false;
IsCompleted = true;
IsCompletedSuccessfully = true;
IsFaulted = false;
Status = RanToCompletion;}

So it printed "Hello" and then returned the completed Task. This proves that the Task was started immediately.

But now look at the following code:

open System.Net
open System
open System.IO

let printTask str =
async {
printfn "%s" str
} |> Async.StartAsTask

let fetchUrlAsync url =
async {
let req = WebRequest.Create(Uri(url))
do! printTask ("started downloading " + url) |> Async.AwaitTask
use! resp = req.GetResponseAsync() |> Async.AwaitTask
use stream = resp.GetResponseStream()
use reader = new IO.StreamReader(stream)
let html = reader.ReadToEnd()
do! printTask ("finished downloading " + url) |> Async.AwaitTask
}

(This is Scott Wlaschin's "Async Web Downloader" example, adapted to use Tasks instead of Asyncs internally).

Here, the async { ... } block contains three Tasks, all of which are wrapped in Async.AwaitTask. (Note that if you removed |> Async.AwaitTask from any of these lines, you'd get a type error). For each Task, once its line of code executes, it will start right away. But that's an important point, because the overall async { ... } computation is not started right away. So I can do:

let a = fetchUrlAsync "http://www.google.com"

And the only thing printed in F# Interactive is val a : Async<unit>. I can wait as long as I want to, and nothing else is printed. Only once I actually start a will it start running:

a |> Async.RunSynchronously

This prints started downloading http://www.google.com immediately, then after a short pause it prints finished downloading http://www.google.com.

So that's the purpose of Async.AwaitTask: to allow async { ... } blocks to more easily interoperate with C# code that returns Tasks. And if the Async.AwaitTask call is inside an async { ... } block, then the Task won't actually start until the enclosing Async is started, so you still get all the advantages of "cold-start" Asyncs.



Related Topics



Leave a reply



Submit