找不到异步等待的简单方法



假设我需要执行一些异步操作,并且我现在需要结果。如果我使用c#,我会这样做:

var contents = await File.ReadAllLinesAsync(...);

重要的是,这是一个非阻塞操作。

我知道Async.RunSynchronously,但文档表明它是阻塞操作,这意味着它不比c#中的Task.Result好。

如果我需要在f#中做同样的事情,我如何读取文件内容而不阻塞?

正如Bartosz的回答所解释的那样,相当于在f#中的async方法中使用await,即在计算表达式块中使用let!。如果你正在处理。net任务,你可以使用task { ... };如果你正在处理f#异步计算,那么你可以使用async { ... }.

要使用async { .. },您还可以使用Async.AwaitTask将任务转换为异步计算:

let run () = async {
let! contents = File.ReadAllLinesAsync "/path" |> Async.AwaitTask
return contents
}

如何实际运行run ()函数?首先,不可能在不阻塞的情况下运行计算并等待结果。如果您需要在同步代码块中得到结果,那么您只需要阻塞即可。这和任务是一样的——你可以让它们在后台运行和完成,在另一个非阻塞任务中使用它们,或者阻塞并等待。

如果您不在另一个async { .. }块中,您可以做两件事:

// Run the task, do something with the result and
// start the whole operation without blocking 
async { 
let! result = run ()
printf "%s" result }
|> Async.Start
// Block and wait for the result using RunSynchronously
let result = 
run ()
|> Async.RunSynchronously

如果你想坚持任务并行库:

open FSharp.Control.Tasks
let run () = task {
let! contents = File.ReadAllLinesAsync "/path"
return contents
}

这里的task { .. }类似于c#中的async Task<T>标记方法,而以!符号结尾的组合符(例如:let!)可以与await比较。

不深入讨论实现细节,主要区别在于task { .. }是一个计算表达式,因此它是可插拔的——在FSharp.Control.Tasks名称空间中默认存在一个,但也有其他实现和库(如Ply)有时提供不同的功能。

最新更新