【问题标题】:F#: purpose of SwitchToThreadPool just before async returnF#:在异步返回之前 SwitchToThreadPool 的目的
【发布时间】:2011-07-22 22:45:33
【问题描述】:

Async.SwitchToNewThread 的 MS 文档中,给出的示例之一是:

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

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

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

【问题讨论】:

    标签: multithreading concurrency asynchronous f#


    【解决方案1】:

    这个例子可能更清楚,因为它没有展示任何真实的场景。

    但是,在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> 类型本质上只是一些获取函数的对象(工作流的其余部分)并且可以在任何地方执行它,但没有其他方法可以“破坏”工作流。

    【讨论】:

    • 谢谢托马斯。你的回答让我对真正发生的事情有了一些很好的了解
    • 如果let original = System.Threading.SynchronizationContext.Currentnull 怎么办?当我从 gui 线程中使用 Async.Parallel |> Async.Start 时,似乎总是为空(并且在 async 块内做一些工作,然后切换到我在并行启动 asyncs 之前掌握的 gui 上下文)。在切换到 gui 上下文并执行一些更新后切换回 null 似乎没有任何害处,但它能让我脱离 gui 线程吗?
    • 没关系,我能够凭经验确认切换到 null 确实会让你脱离 gui 线程(但不确定它会去哪里)。无论如何,谢谢!
    • @StephenSwensen,如果SynchrnoizationContext.Currentnull,并且您调用PostSend 方法,它将在线程池线程上执行。 - 另见msdn.microsoft.com/en-us/magazine/gg598924.aspx
    猜你喜欢
    • 2014-11-26
    • 1970-01-01
    • 2021-06-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多