任务并行库与异步工作流

时间:2009-12-09 01:55:54

标签: f# asynchronous task-parallel-library

我有一些用c#编写的执行并发代码的东西,大量使用任务并行库(Task and Future continuation chains)。

我现在将其移植到F#并试图找出使用F#Async工作流与TPL中的构造的优缺点。我倾向于TPL,但我认为无论哪种方式都可以。

有没有人有关于在F#中编写并发程序的提示和智慧来分享?

2 个答案:

答案 0 :(得分:28)

这个名称几乎总结了差异:异步编程与并行编程。但是在F#你可以混合搭配。

F#异步工作流程

当您希望异步执行代码时,F#异步工作流非常有用,即启动任务而不是等待最终结果。最常见的用法是IO操作。让你的线程坐在空闲循环中等待你的硬盘完成写入会浪费资源。

如果以异步方式开始写操作,则可以暂停该线程并稍后通过硬件中断唤醒它。

任务并行库

.NET 4.0中的任务并行库抽象出任务的概念 - 例如解码MP3或从数据库中读取一些结果。在这些情况下,您实际上需要计算结果,并在稍后的某个时间点等待操作的结果。 (通过访问.Result属性。)

您可以轻松地混合和匹配这些概念。比如在TPL Task对象中执行所有IO操作。对于程序员来说,你已经抽象出需要“处理”那个额外的线程,但是你在浪费资源。

同样,您可以创建一系列F#异步工作流并并行运行它们(Async.Parallel),但是您需要等待最终结果(Async.RunSynchronously)。这使您无需显式启动所有任务,但实际上您只是并行执行计算。

根据我的经验,我发现TPL更有用,因为通常我想并行执行N个操作。但是,当存在“幕后”的某些内容时,F#异步工作流是理想的,例如Reactive Agent或Mailbox类型的东西。 (您发送消息,处理它并将其发回。)

希望有所帮助。

答案 1 :(得分:2)

在4.0中我会说:

  • 如果您的功能是连续的,请使用Async工作流程。他们只是阅读得更好。
  • 将TPL用于其他所有事情。

也可以混合搭配。他们添加了对将工作流作为任务运行并使用TaskFactory.FromAsync创建遵循异步开始/结束模式的任务的支持,TPL等效于Async.FromBeginEndAsync.BuildPrimitive

let func() =
    let file = File.OpenRead("foo")
    let buffer = Array.zeroCreate 1024
    let task1 = Task.Factory.FromAsync(file.BeginRead(buffer, 0, buffer.Length, null, null), file.EndRead)
    task1.Start()

    let task2 = Async.StartAsTask(file.AsyncRead(1024))
    printfn "%d" task2.Result.Length

值得注意的是,Async Workflows运行时和TPL都将创建一个额外的内核原语(一个事件)并使用WaitForMultipleObjects来跟踪I / O完成,而不是使用完成端口和回调。在某些应用中这是不合需要的。