我这样定义了await函数:
let await (task : Task<'a>) =
task |> Async.AwaitTask |> Async.RunSynchronously
和两个类似的任务:
let stringTask = new Task<string>(fun () -> "something")
let unitTask = new Task(fun () -> printf "something")
这样称呼他们:
let stringResult = await stringTask
await unitTask
但是第二个不是通用的,因此我无法调用await
,因此我像下面这样编辑了函数参数:
let await (task : Task) =
task |> Async.AwaitTask |> Async.RunSynchronously
问题是现在await stringTask
返回unit
而不是string
。
我应该如何编写await函数来接受Task <'a>和Task作为参数并等待它?
答案 0 :(得分:5)
您对await
的原始定义很好。
问题出在unitTask
上,它不是通用的。以与stringTask
相同的方式使其通用:
let unitTask = new Task<unit>(fun () -> printf "something")
如果要同时处理通用Task<'a>
和非通用Task
,则有2个选择。
创建2个await
函数(以函数方式):
let await (task : Task<'a>) = task |> Async.AwaitTask |> Async.RunSynchronously
let awaitUnit (task : Task ) = task |> Async.AwaitTask |> Async.RunSynchronously
或创建2个Await
成员,例如类型为Task
(OO方法):
type Task with
static member Await (task : Task ) = task |> Async.AwaitTask |> Async.RunSynchronously
static member Await (task : Task<'a>) = task |> Async.AwaitTask |> Async.RunSynchronously
按惯例,成员使用Pascal大小写,因此我使用Await
而不是await
。
在致电task.Start()
之前,请记住先致电await
。
答案 1 :(得分:5)
curselection()
已经对Async.AwaitTask
和Task<'a>
都进行了重载,因此除非您确实需要帮助函数,否则可以直接使用它:
Task
如果这是您的实际代码,并且确实需要阻止线程等待这些结果,则也可以直接使用Task API来保存Task->异步翻译开销:
let stringResult = Async.AwaitTask stringTask |> Async.RunSynchronously
Async.AwaitTask unitTask |> Async.RunSynchronously
答案 2 :(得分:1)
您可以创建一个Task -> Task<unit>
辅助函数,以将从API中获得的Task
个对象转换为Task<unit>
。我怀疑这不是最好的方法,因为已经有一段时间了,因为我一直非常关注F#异步与框架基于任务的异步之间的区别,但这在您的琐碎扩展中起作用例如:
open System.Threading
open System.Threading.Tasks
let toUnitTask (t : Task) =
new Task<_>(fun () -> t.Start(); t |> Async.AwaitTask |> Async.RunSynchronously)
let await (task : Task<_>) =
task |> Async.AwaitTask |> Async.RunSynchronously
let stringTask = new Task<string>(fun () -> Thread.Sleep 3000; "something")
let unitTask = new Task(fun () -> Thread.Sleep 2000; printfn "something") |> toUnitTask
stringTask.Start()
unitTask.Start()
let stringResult = await stringTask
await unitTask