【问题标题】:Round robin concurrent algorithm with F# and Task<T>使用 F# 和 Task<T> 的循环并发算法
【发布时间】:2017-07-10 16:27:19
【问题描述】:

我有一个这样的 C# API:

Task<T> Foo(serverUri)

假设我有 4 个可能的 serverUris。我想实现一个返回 DiscUnionBar 类型的函数:

type DiscUnionBar of T =
    Safe of T | Weak of T | ConnectionError

实施将具有以下要求:

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

鉴于我不能使用 F# 的 Async 并且必须坚持使用 C# 的 Task 用法,这是否容易做到?我对这个有点迷茫。

【问题讨论】:

  • 有什么理由不能使用async

标签: asynchronous concurrency f#


【解决方案1】:

除非有一个原因你不能在你的代码中使用Asyncanywhere,并且你唯一的限制是Foo必须返回一个Task,你应该没有问题转换Task 是由使用 Async.AwaitTask 调用 FooAsync 产生的。

通过这种方式,您可以使用 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 *)
}

我对@9​​87654322@ 库也有很好的经验,它可以让您直接在异步计算表达式中使用Task,而无需显式调用AwaitTask,并且通常有助于异步/任务互操作。虽然有些人可能不喜欢它试图隐藏任务。

【讨论】:

  • 有些人不喜欢 async 在调用 HttpClient、ADO.NET、EF、AWS SDK、Azure SDK 等异步 API 时强制使用 Async.AwaitTask - 简而言之,所有非 F# 异步 API
  • @PanagiotisKanavos 这正是我提到图书馆的原因:)
猜你喜欢
  • 2023-03-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-23
  • 2011-11-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多