使用F#和Task <T>的循环并发算法

ymp*_*tor 3 concurrency f# asynchronous

我有一个像这样的C#API:

Task<T> Foo(serverUri)
Run Code Online (Sandbox Code Playgroud)

假设我有4个可能的服务器.我想实现一个将返回DiscUnionBar类型的函数:

type DiscUnionBar of T =
    Safe of T | Weak of T | ConnectionError
Run Code Online (Sandbox Code Playgroud)

实施将具有以下要求:

  1. 使用3个不同的serverUris对Foo()进行3次(最大)并发调用.
  2. 选择2个最快的成功回复.如果它们给出相同的结果T1和T2(T1 == T2),则停止执行并发请求并忽略/取消正在进行的请求并返回T的安全性.如果T1!= T2,继续执行更多请求(或查看响应)直到找到两个相同的响应.
  3. 如果任何请求失败(抛出ServerException),请尝试使用之前未请求的serverUri.
  4. 如果对所有4个服务器的所有请求都失败,则返回ConnectionError.
  5. 如果只有1个请求成功,则返回T的弱点.

考虑到我不能使用F#的Async并且必须坚持使用C#的Task任务,这很容易吗?我在这一点上有点失落.

Hon*_*tan 6

除非是你不能使用的原因Async 随时随地在你的代码,你唯一的限制就是Foo必须返回一个Task,你应该没有问题转换Task与调用产生Foo一个AsyncAsync.AwaitTask.

这样你就可以使用F#的异步计算表达式构建逻辑,就像Foo返回一样Async

let simpleComputation serverUri = async {
    let! fooResult = Foo(serverUri) |> Async.AwaitTask
    (* here you can work with the T returned by Foo's task *)
}
Run Code Online (Sandbox Code Playgroud)

我也有很好的FSharp.Control.FusionTasks库经验,它允许你Task直接在异步计算表达式中使用,而不必AwaitTask显式调用,并且通常有助于异步/任务互操作.虽然有些人可能不喜欢它试图隐藏任务.