我是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方法将在此时运行代码同步。
有什么区别(我认为必须有),何时应该使用一种方法而不是另一种?
答案 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个可用线程进行打印(这几乎没有时间)。