有没有办法让F#中的异步工作流程自动生成?

Dax*_*ohl 3 workflow f# asynchronous

(注意我正在谈论流水线操作,如并行运行独立进程;与|>运算符无关).

所以,如果我有两个功能

let incr x = 
  Thread.Sleep 1000
  x + 1

let product x y = 
  Thread.Sleep 1000
  x * y
Run Code Online (Sandbox Code Playgroud)

是否有一种简单的方法来编写像(伪代码)这样​​的工作流程

let productOfIncrements x y = 
  async {
    let! x1 = incr x
    let! y1 = incr y
    let! result = product x1 y1
    return result
  }
Run Code Online (Sandbox Code Playgroud)

管道前两个独立的操作,因此在两秒钟内执行,或异步工作流程是否解决了这个问题?如果有一个很好的解决问题的方法,是否有一种直接的方法来扩展这样的方法,比如在N + 1秒而不是2N中进行递归因子计算?

Tom*_*cek 6

最简单的选择是使用Async.StartChild.这个原始启动在后台(在线程池中)启动异步操作,并返回一个"令牌",可用于等待操作的完成.这不会阻止工作流,因此您可以继续运行其他操作:

let productOfIncrements x y = 
  async {
    // Start the 'incr x' operation in background
    let! x1Op = async {return incr x} |> Async.StartChild
    // Continue doing other work 
    // (synchronously since it takes the same time as the above.)
    let y1 = incr y
    // Now wait for the result of 'incr x' (if it is still running)
    let! x1 = x1Op
    // return the product (just call the function synchronously)
    return product x1 y1
  }
Run Code Online (Sandbox Code Playgroud)

如果两个操作返回相同的类型,那么您也可以使用Async.Parallel,它组成多个操作并行运行.

如果您正在使用纯粹的CPU绑定计算并且需要创建大量计算,那么您也可以Tasks直接使用.NET (例如参见本文).任务更有效,但使用起来并不优雅(并且不支持异步等待).

作为旁注,通常使用术语管道(至少在F#或.NET世界中)用于更复杂的事情 - 例如,假设您有一系列相互依赖的步骤.处理多个输入时,您可以并行运行这些步骤(并且仍然限制总的并行度).这也可以使用F#异步工作流完成 - 例如参见本文.还有一个名为pipelets框架实现了这个概念.