假设我需要执行一些异步操作,并且我现在需要结果。如果我使用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)有时提供不同的功能。