3

I'm writing an F# application and I want to get rid of explicit references to task as much as possible. Is the following equivalent to Task.Run or am I missing something?

[<AutoOpen>]
module Async =        
    let inline runInThreadPool backgroundTask = async {
          let originalContext = System.Threading.SynchronizationContext.Current
          do! Async.SwitchToThreadPool()
          let! result = backgroundTask()
          do! Async.SwitchToContext originalContext 
          return result}

Example usage (untested):

async { // starts on the UI thread
    let! result = Async.runInThreadPool(fun _ -> async {
        let mutable sum= 0
        for i in 1..10000 do
            sum <- sum + 1
        return sum })
    //do something with the result in the UI
} |> Async.StartImmediate
N_A
  • 19,799
  • 4
  • 52
  • 98
  • I don't get what this is supposed to achieve. What does it have to do with `Task`? `Task.Run` is equivalent to `Async.Start`. – Daniel Jun 16 '14 at 15:52
  • Are you using APIs that deal with tasks? If so, you can easily convert those to `Async`s using `Async.AwaitTask`. In any case, I don't see the value in writing a replacement for `Async.Start`. – Daniel Jun 16 '14 at 15:57
  • Ah, gotcha. I want to background some processing, and am currently using `Task.Run` with `Async.AwaitTask`. I'm wanting to replace the `Task.Run`s with `Async`, so I want to know if the posted code is equivalent (i.e. runs on a background thread, but runs the continuation on the original thread). – N_A Jun 16 '14 at 16:01
  • I'm not sure about the threading behavior, but just comparing the docs for `Task.Run` and `Async.Start`, it seems they're the same. – Daniel Jun 16 '14 at 16:10
  • The problem there is that it returns `unit` so there isn't any way to unwrap it using `let!`. – N_A Jun 16 '14 at 16:11
  • Can you show a code sample? – Daniel Jun 16 '14 at 16:17
  • @Daniel Obviously contrived, but I think it illustrates what I'm looking for. – N_A Jun 16 '14 at 16:24
  • 1
    The `async { }` block already runs in the thread pool. You can just change `let! result = Async.runInThreadPool(fun _ -> async {` to `let! result = async {`. – Daniel Jun 16 '14 at 16:35
  • @Daniel I checked the `System.Threading.Thread.CurrentThread.ManagedThreadId` and that isn't the case. A simple `Async` bind does not run on a new thread, while the code I gave does. – N_A Jun 16 '14 at 17:20
  • Right. It may not, or it may. Do you really care? – Daniel Jun 16 '14 at 18:51
  • That makes a pretty big difference with respect to UI responsiveness. I want to guarantee it doesn't lock up the UI. – N_A Jun 16 '14 at 18:55
  • You are apparently already in an `async { }` block when you first check the thread Id. – Daniel Jun 16 '14 at 19:32
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/55729/discussion-between-mydogisbox-and-daniel). – N_A Jun 16 '14 at 20:03

1 Answers1

1

As @Daniel pointed out, this is better achieved using Async.StartChild like this:

[<AutoOpen>]
module Async =        
    let inline runInThreadPool backgroundTask = async {
          let! result = backgroundTask() |> Async.StartChild
          return! result}
N_A
  • 19,799
  • 4
  • 52
  • 98