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

Sam*_*Sam 2 .net f# asynchronous

我是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
Run Code Online (Sandbox Code Playgroud)

我试图理解与其do! Async.Sleep 2000相反的需要do Threading.Thread.Sleep(2000).

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

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

Tom*_*cek 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
Run Code Online (Sandbox Code Playgroud)

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

运行第二个for循环后,您将看到1秒钟后立即打印"完成"消息.这是因为异步等待实际上并没有阻塞线程,因此5个定时器将全部经过,然后使用1个可用线程进行打印(这几乎不需要时间).