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

Can't find simple way to wait asynchronously

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

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

这里的重要部分是它是非阻塞操作。

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

如果我需要在 F# 中执行相同的操作,我如何在不阻塞的情况下读取文件内容?

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

open FSharp.Control.Tasks

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

这里的task { .. }类似于C#中的async Task<T>标记方法,而以!符号结尾的组合子(例如let!)可以与[=进行比较15=].

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

正如 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