任务并行库vs异步工作流。

时间:2021-11-25 02:23:30

I have some stuff written in c# that executes concurrent code, making heavy use of the Task Parallel Library (Task and Future continuation chains).

我有一些用c#编写的东西,它执行并发代码,大量使用任务并行库(任务和未来的延续链)。

I'm now porting this to F# and am trying to figure out the pros and cons of using F# Async workflows vs. the constructs in the TPL. I'm leaning towards TPL, but I think it could be done either way.

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

Does anyone have tips and wisdom about writing concurrent programs in F# to share?

有人有关于在f#中编写并发程序的技巧和智慧吗?

2 个解决方案

#1


28  

The name pretty much sums up the difference: asynchronous programming vs. parallel programming. But in F# you can mix and match.

这个名称很好地概括了区别:异步编程与并行编程。但是在f#中你可以混合和匹配。

F# Asynchronous Workflows

F# async workflows are helpful when you want to have code execute asynchronously, that is starting a task and not waiting around for the final result. The most common usage of this is IO operations. Having your thread sit there in an idle loop waiting for your hard disk to finish writing wastes resources.

当您想要异步地执行代码时,f# async工作流是有帮助的,这是开始一个任务,而不是等待最后的结果。最常见的使用是IO操作。让您的线程处于空闲循环中,等待您的硬盘完成写浪费资源。

If you began the write operation asynchronously you can suspend the thread and have it woken up later by a hardware interrupt.

如果您异步地开始写操作,您可以挂起线程,然后在稍后的硬件中断中唤醒它。

Task Parallel Library

The Task Parallel Library in .NET 4.0 abstracts the notion of a task - such as decoding an MP3, or reading some results from a database. In these situations you actually want the result of the computation and at some point in time later are waiting for the operation's result. (By accessing the .Result property.)

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

You can easily mix and match these concepts. Such as doing all of your IO operations in a TPL Task object. To the programmer you have abstracted the need to 'deal with' that extra thread, but under the covers you're wasting resources.

您可以轻松地混合和匹配这些概念。例如在一个TPL任务对象中执行所有的IO操作。对于程序员,您已经抽象了需要“处理”额外的线程,但是在覆盖范围内,您是在浪费资源。

Like wise you can create a series of F# async workflows and run them in parallel (Async.Parallel) but then you need to wait for the final result (Async.RunSynchronously). This frees you from needing to explicitly start all the tasks, but really you are just performing the computation in parallel.

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

In my experience I find that the TPL is more useful because usually I want to execute N operations in parallel. However, F# async workflows are ideal when there is something that is going on 'behind the scenes' such as a Reactive Agent or Mailbox type thing. (You send something a message, it processes it and sends it back.)

根据我的经验,我发现TPL更有用,因为通常我希望并行执行N个操作。然而,当有一些事情发生在“幕后”,比如反应性代理或邮箱类型的东西时,f# async工作流是理想的。(你发送一个消息,它处理它并将它发送回来。)

Hope that helps.

希望有帮助。

#2


2  

In 4.0 I would say:

在4.0中,我会说:

  • If your function is sequential, use Async workflows. They simply read better.
  • 如果您的函数是顺序的,请使用异步工作流。他们只是阅读更好。
  • Use the TPL for everything else.
  • 其他的都用TPL。

It's also possible to mix and match. They've added support for running a workflow as a task and creating tasks that follow the async Begin/End pattern using TaskFactory.FromAsync, the TPL equivalent of Async.FromBeginEnd or Async.BuildPrimitive.

也可以混合搭配。他们增加了对运行工作流作为任务的支持,并使用TaskFactory创建了遵循async开始/结束模式的任务。FromAsync, TPL相当于异步。FromBeginEnd或Async.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

It's also worth noting that both the Async Workflows runtime and the TPL are going to create an extra kernel primitive (an Event) and use WaitForMultipleObjects to track I/O completion, rather than using completion ports and callbacks. This is undesirable in some applications.

同样值得注意的是,Async工作流运行时和TPL都将创建一个额外的内核原语(一个事件),并使用waitformpleobjects来跟踪I/O完成,而不是使用完成端口和回调。这在某些应用程序中是不可取的。

#1


28  

The name pretty much sums up the difference: asynchronous programming vs. parallel programming. But in F# you can mix and match.

这个名称很好地概括了区别:异步编程与并行编程。但是在f#中你可以混合和匹配。

F# Asynchronous Workflows

F# async workflows are helpful when you want to have code execute asynchronously, that is starting a task and not waiting around for the final result. The most common usage of this is IO operations. Having your thread sit there in an idle loop waiting for your hard disk to finish writing wastes resources.

当您想要异步地执行代码时,f# async工作流是有帮助的,这是开始一个任务,而不是等待最后的结果。最常见的使用是IO操作。让您的线程处于空闲循环中,等待您的硬盘完成写浪费资源。

If you began the write operation asynchronously you can suspend the thread and have it woken up later by a hardware interrupt.

如果您异步地开始写操作,您可以挂起线程,然后在稍后的硬件中断中唤醒它。

Task Parallel Library

The Task Parallel Library in .NET 4.0 abstracts the notion of a task - such as decoding an MP3, or reading some results from a database. In these situations you actually want the result of the computation and at some point in time later are waiting for the operation's result. (By accessing the .Result property.)

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

You can easily mix and match these concepts. Such as doing all of your IO operations in a TPL Task object. To the programmer you have abstracted the need to 'deal with' that extra thread, but under the covers you're wasting resources.

您可以轻松地混合和匹配这些概念。例如在一个TPL任务对象中执行所有的IO操作。对于程序员,您已经抽象了需要“处理”额外的线程,但是在覆盖范围内,您是在浪费资源。

Like wise you can create a series of F# async workflows and run them in parallel (Async.Parallel) but then you need to wait for the final result (Async.RunSynchronously). This frees you from needing to explicitly start all the tasks, but really you are just performing the computation in parallel.

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

In my experience I find that the TPL is more useful because usually I want to execute N operations in parallel. However, F# async workflows are ideal when there is something that is going on 'behind the scenes' such as a Reactive Agent or Mailbox type thing. (You send something a message, it processes it and sends it back.)

根据我的经验,我发现TPL更有用,因为通常我希望并行执行N个操作。然而,当有一些事情发生在“幕后”,比如反应性代理或邮箱类型的东西时,f# async工作流是理想的。(你发送一个消息,它处理它并将它发送回来。)

Hope that helps.

希望有帮助。

#2


2  

In 4.0 I would say:

在4.0中,我会说:

  • If your function is sequential, use Async workflows. They simply read better.
  • 如果您的函数是顺序的,请使用异步工作流。他们只是阅读更好。
  • Use the TPL for everything else.
  • 其他的都用TPL。

It's also possible to mix and match. They've added support for running a workflow as a task and creating tasks that follow the async Begin/End pattern using TaskFactory.FromAsync, the TPL equivalent of Async.FromBeginEnd or Async.BuildPrimitive.

也可以混合搭配。他们增加了对运行工作流作为任务的支持,并使用TaskFactory创建了遵循async开始/结束模式的任务。FromAsync, TPL相当于异步。FromBeginEnd或Async.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

It's also worth noting that both the Async Workflows runtime and the TPL are going to create an extra kernel primitive (an Event) and use WaitForMultipleObjects to track I/O completion, rather than using completion ports and callbacks. This is undesirable in some applications.

同样值得注意的是,Async工作流运行时和TPL都将创建一个额外的内核原语(一个事件),并使用waitformpleobjects来跟踪I/O完成,而不是使用完成端口和回调。这在某些应用程序中是不可取的。