我非常喜欢F#的 async
机制,但是对我来说,它有一个严重的问题:它不允许创建工作流,这些工作流的执行时间不能超过某个特定的时间间隔。
为了更清楚地说明,这里有一个我为自己编写的简单函数:
let withTimeout operation timeout = async {
try
return Some <| Async.RunSynchronously (operation, timeout)
with :? TimeoutException -> return None
}
即签名为
val withTimeout : operation:Async<'a> -> timeout:int -> Async<'a option>
这里是示例用法:
let op = async {
do! Async.Sleep(1000)
return 1
}
#time
withTimeout op 2000 |> Async.RunSynchronously;;
// Real: 00:00:01.116, CPU: 00:00:00.015, GC gen0: 0, gen1: 0, gen2: 0
// val it : unit option = Some 1
withTimeout op 2000 |> Async.RunSynchronously;;
// Real: 00:00:01.004, CPU: 00:00:00.000, GC gen0: 0, gen1: 0, gen2: 0
// val it : unit option = Some 1
withTimeout op 500 |> Async.RunSynchronously;;
// Real: 00:00:00.569, CPU: 00:00:00.000, GC gen0: 0, gen1: 0, gen2: 0
// val it : unit option = None
你可以看到,它按预期工作。它非常好,但也有点尴尬,我不确定它的安全性和可能出现的其他问题。也许我正在重新发明轮子,也许有一种好的、简洁的方法来编写这样的工作流程?
Async.RunSynchronously
时,如果底层异步操作是I/O绑定的,你会阻塞当前线程并且失去效率。我认为我还没有看到过一个在实际中工作的实现,但我记得使用了一个丑陋的hack来将异步组件转换为可观察对象,然后合并它们。 - MisterMetaphorRunSynchronously
封装到另一个async
中。我猜这样可以保持并发性。但是,我同意这很丑陋。我更关心@Lee说的-我实际上并没有杀死正在运行的任务。但是目前我不知道如何修复它。 - Rustam