我在F#控制台应用程序的main函数中有以下代码。
let main ... =
let list = // get a list
list
|> Seq.iter(fun i -> ....)
()
然后我尝试并行运行这些项目。
let list = // get a list
list
|> Seq.map(fun i -> async { .... })
|> Seq.toArray
|> Async.Parallel
|> Async.RunSynchronously // ERROR
// |> ignore
()
它出现了错误
Error FS0001 This expression was expected to have type 'unit' but here has type 'unit []'
添加|> ignore
会导致F#无法运行Seq.map()
中的代码。
答案 0 :(得分:3)
我故意不回答你的问题。相反,如果您偶尔偶然发现异步工作流程,我将分享您可能用于救援的方法。诀窍是完全接受F#推广的探索性编程风格。
让我们从最小的异步工作流程开始,可能是async { () }
。在FSI评估
let dummywf = async { () }
产量
val dummywf : Async<unit>
显示dummywf
值确实是异步工作流程(虽然是非虚拟的)。
异步工作流程可以组成序列,最简单的一个可能是列表[ dummywf ]
。评估它会显示Async<unit> list
类型,它代表了所寻求的类型。
现在,让我们回想一下Async.Parallel
method的签名,即seq<Async<'T>> -> Async<'T[]>
,即它需要一系列异步计算并将其转换为异步计算,最终通过异步计算其成员来评估产生一个值'T
的数组。检查FSI,表达式
[ dummywf ] |> Async.Parallel
确实评估为Async<unit []>
类型的值。
最后,让我们通过使用最简单的Async.RunSynchronously<'T>
method 形式将其组合成一个Async&lt;'T&gt;来实现这个值。 (在我们的示例中为类型Async<unit []>
的值)并返回类型'T
的评估结果(在我们的示例中为unit []
。评估组合表达式
[ dummywf ] |> Async.Parallel |> Async.RunSynchronously
按预期收取[|()|]
。
在清楚地理解了上述构图之后,表现得如预期的那样,但是为了证明我们真的构建了一个完整的异步工作流程,让我们尝试一些简单但更令人印象深刻的东西。让我们实现一个int -> Async<unit>
类型的函数,它接受int
参数,进行非阻塞暂停,返回相同的unit
,并且副作用打印参数的值:
let wasteSomeTime x =
async {
do! Async.Sleep(100)
printfn "%d" x
}
现在让我们使用wasteSomeTime
组成一系列具有不同参数的异步计算,并在类似于前一种情况的组合中对其进行评估:
let wasteful = [1..10] |> Seq.map wasteSomeTime // binds to seq<Async<unit>>
wasteful |> Async.Parallel |> Async.RunSynchronously |> ignore
输出类似于
>
4
2
3
6
8
10
7
5
9
1
val it : unit = ()
确实说明了异步执行。
在浏览了上面的小型探索课程后,我很肯定你能够自己回答原来的问题。