为什么需要使用"做!异步" F#异步工作流中的样式函数?

时间:2015-10-16 12:49:13

标签: .net asynchronous f#

我是F#Async工作流程的新手。通常,介绍此主题的代码和示例包含以下(简化)示例:

let sleepWorkflow = 
    async{
        printfn "Starting sleep workflow at %O" DateTime.Now.TimeOfDay
        do! Async.Sleep 2000
        printfn "Finished sleep workflow at %O" DateTime.Now.TimeOfDay
    }

Async.RunSynchronously sleepWorkflow

我正在尝试了解do! Async.Sleep 2000而不是do Threading.Thread.Sleep(2000)的必要性。

根据我的理解,BOTH方法将在此时运行代码同步

有什么区别(我认为必须有),何时应该使用一种方法而不是另一种?

1 个答案:

答案 0 :(得分:7)

不同之处在于使用Thread.Sleep阻止当前线程,以便在Async.Sleep创建系统计时器时不会执行任何其他操作,释放当前线程(以便它可以执行其他操作)然后(经过一段时间后)再次获取一个线程并运行剩下的代码。

如果您有大量并行运行的async工作流(因为每个工作站都有一个专用线程会很昂贵)或者在GUI线程上运行代码(只有一个线程),这很重要你不应该阻止它。)

为了更好地理解这一点,您可以将线程池​​线程数更改为1,并使用同步和异步阻塞尝试以下代码:

System.Threading.ThreadPool.SetMinThreads(1, 1)
System.Threading.ThreadPool.SetMaxThreads(1, 1)

for i in 1 .. 5 do
  async { System.Threading.Thread.Sleep(1000)
          printfn "Done" } |> Async.Start

for i in 1 .. 5 do
  async { do! Async.Sleep(1000)
          printfn "Done" } |> Async.Start

在运行第一个for循环后,您将打印“完成”消息,延迟时间为1秒(因为一个线程被反复阻止1秒)。

运行第二个for循环后,您会在1秒后看到“完成”消息一次全部打印出来。这是因为异步等待实际上并没有阻塞线程,因此5个计时器将全部经过,然后使用1个可用线程进行打印(这几乎没有时间)。