F#使用Async.Parallel并行运行2个任务

时间:2013-04-05 03:01:20

标签: asynchronous f#

假设我有这两个功能:

let dowork n =
    async {
        do printfn "work %d" n
    }

let work i = async {
  do! Async.Sleep(2000)
  printfn "work finished %d" i }

我如何使用Async.Parallel同时运行它们并在继续之前等待两者完成?

3 个答案:

答案 0 :(得分:27)

如前所述,您只需将异步函数放入序列中并将其传递给Async.Parallel

但是,如果您需要执行返回不同类型结果的不同作业,则可以使用Async.StartChild

let fn1 = async {
        do! Async.Sleep 1000
        printfn "fn1 finished!"
        return 5
    }

let fn2 = async {
        do! Async.Sleep 1500
        printfn "fn2 finished!"
        return "a string"
    }

let fncombined = async {
        // start both computations simultaneously
        let! fn1 = Async.StartChild fn1
        let! fn2 = Async.StartChild fn2

        // retrieve results
        let! result1 = fn1
        let! result2 = fn2

        return sprintf "%d, %s" (result1 + 5) (result2.ToUpper())
    }

fncombined
|> Async.RunSynchronously
|> printfn "%A"

答案 1 :(得分:13)

Async.Parallel采用一系列异步。在这种情况下,我将它传递给列表。

[dowork 1; work 2]
|> Async.Parallel
|> Async.RunSynchronously
|> ignore

如果要返回不同类型的数据,请使用Discriminated Union

type WorkResults =
    | DoWork of int
    | Work of float32

let dowork n =
    async {
        do printfn "work %d" n
        return DoWork(n)
    }

let work i = async {
  do! Async.Sleep(2000)
  printfn "work finished %d" i 
  return Work(float32 i / 4.0f)
}

[dowork 1; work 2]
|> Async.Parallel
|> Async.RunSynchronously
|> printf "%A"

输出

work 1
work finished 2
[|DoWork 1; Work 0.5f|]

答案 2 :(得分:0)

当编译时任务数量固定时,我喜欢有这样的辅助函数:

module Async = 

  let parallel2 a b = 
    async {
      // Start both tasks
      let! x = Async.StartChild a
      let! y = Async.StartChild b

      // Wait for both to finish
      let! i = x
      let! j = y

      // Return both results as a strongly-typed tuple
      return i, j
    }

这样的用法:

let work1 = async { return 1 }

let work2 = async { return "a" }

let work1And2 = 
  async {
    let! (a, b) = Async.parallel2 work1 work2

    printfn "%i %s" a b
  }

注意任务的不同类型。这可能非常有用!

我们可以为 Async<Unit> 添加一个额外的帮助器,因为 ()((), ()) 具有相同的语义:

module Async = 

  // ...

  let doParallel2 (a : Async<Unit>) (b : Async<Unit>) =
    parallel2 a b
    |> Async.Ignore

然后应用于您的场景:

async {
  do! Async.doParallel2 (dowork 1) (work 2)
}