此表达式应具有类型 'unit',但此处具有 Async.Parallel |> Async.RunSyncly 的类型 'unit []'

  • 本文关键字:Async 类型 unit RunSyncly 表达式 Parallel f#
  • 更新时间 :
  • 英文 :


我在 F# 控制台应用程序的主函数中有以下代码。

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
()

它得到了错误

错误 FS0001 此表达式应具有类型 "单位"    但这里有类型 "单位 []"

添加|> ignore将导致 F# 无法运行Seq.map()中的代码。

我故意不回答你的问题本身。相反,我将分享一种方法,如果您偶尔偶然发现异步工作流,您可以使用该方法进行救援。诀窍是完全采用 F# 推广的探索性编程风格。

让我们从一个最小的异步工作流开始,这可能是async { () }.在 FSI 中进行评估

let dummywf = async { () }

收益 率

val dummywf : Async<unit>

显示dummywf值确实是一个异步工作流(尽管是一个非常虚拟的工作流(。

异步工作流可以组合成序列,最简单的一种可能是列表[ dummywf ]。评估它揭示了类型Async<unit> list,它代表了所寻求的类型。

现在,让我们回顾一下Async.Parallel方法的签名,它是seq<Async<'T>> -> Async<'T[]>的,即它采用一系列异步计算并将其转换为异步计算,最终通过异步评估其成员进行评估将产生'T值数组。签入 FSI,表达式

[ dummywf ] |> Async.Parallel

计算为类型Async<unit []>的值,确实。

最后,让我们通过最简单的Async.RunSynchronously<'T>方法组合它来实现这个值,该方法采用 Async<'T>(在我们的例子中是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 = ()

这确实证明了异步执行。

在摸索了上面小型探索会议的点点滴滴之后,我相信您将能够自己回答您的原始问题。

相关内容

最新更新