F#:在异步返回之前的SwitchToThreadPool的目的

时间:2011-03-25 13:55:35

标签: multithreading concurrency asynchronous f#

Async.SwitchToNewThread的MS文档中,给出的一个例子是:

let asyncMethod f = 
    async {  
        do! Async.SwitchToNewThread() 
        let result = f() 
        do! Async.SwitchToThreadPool() 
        return result
    } 

在return语句之前切换到线程池的目的是什么?我理解为什么当异步块有更多的工作要做时你可能想要从专用线程切换到线程池,但这不是这种情况。

这不是主要问题的一部分,但我也很想知道为什么SwitchToNewThread和SwitchToThreadPool会返回异步。有没有一个用例,你不想立即“做!”这些任务?谢谢

1 个答案:

答案 0 :(得分:11)

示例可能更清晰,因为它没有展示任何真实场景。

但是,有一个很好的理由在return之前切换到另一个线程。原因是调用函数的工作流(例如asyncMethod)将继续在返回之前切换到的上下文/线程中运行。例如,如果你写:

Async.Start (async {
  // Starts running on some thread (depends on how it is started - 'Async.Start' uses
  // thread pool and 'Async.StartImmediate' uses the current thread
  do! asyncMethod (fun () -> 
      Thread.Sleep(1000) ) // Blocks a newly created thread for 1 sec
  // Continues running on the thread pool thread 
  Thread.Sleep(1000) }) // Blocks thread pool thread

我认为示例中使用的模式不太正确 - 异步工作流应始终返回到启动它们的SynchronizationContext(例如,如果工作流在GUI线程上启动,则可以切换到一个新线程,但应该返回到GUI线程)。如果我正在编写asyncMethod函数,我会使用:

let asyncMethod f = async {  
    let original = System.Threading.SynchronizationContext.Current
    do! Async.SwitchToNewThread() 
    let result = f() 
    do! Async.SwitchToContext(original)
    return result } 

要回答第二个问题 - SwitchTo操作返回Async<unit>并需要使用do!调用的原因是无法直接切换到其他线程。使用do!let! Async<T>类型基本上只是一些获取函数的对象(工作流的其余部分)并且可以在任何需要的地方执行它,但没有其他方法可以“破坏”工作流。