1

问题总结:

  1. Stream.WriteAsync 和 Stream.ReadAsync 是否不会相互阻塞并且可以在 2 个 cpu 内核上完全并行运行?
  2. 有没有办法通知等待外部源异步通知?
  3. MailboxProcessor 作为 TcpClient 的包装器对性能有何影响?

一些解释:

正如我从 Stream.cs 异步操作的源代码中了解到的那样,同步完成而不是完全并行(如果您读取某些内容,它会阻止其他读取尝试直到完成,并且还会阻止写入尝试,以其他方式相同 - 写入阻止读取和写入尝试) ,唯一的好处是它不会阻塞调用 writeAsync/readAsync 的线程

所以我已经将 TcpClient 包装到接受的 MailboxProcessor 中

type AgentRequest<'a> =
  | Write of 'a
  | Read  of int * AsyncReplyChannel<'a>

它的目的是在连接失败时重新连接客户端,在此期间我们不想尝试读取或写入任何内容。这也可以通过线程同步技术实现,但这需要更多的代码。

当我可以对解决方案进行基准测试时,我没有找到合适的位置,但是是否有任何 MailboxProcessor 内部基准测试,以查看它将对 tcp 连接产生什么影响(如果就整个请求/响应时间而言性能影响很小)

这也是为了向服务器发送请求以保证响应顺序与收到的请求相同但我不能依赖Write requestA->Read responseA读取正确的响应:tread1: Write requestA Read responseA tram2: Write requestB Read responseB

队列:['写请求A'; '写请求B'; '阅读响应B'; 'read responseA'] 这将导致responseA 将返回给thread2,responseB 将返回给thread1。

好在请求-响应与请求中设置的 id 相关联。所以这个协议有一些解决方案来存储Dictionary<id, TaskCompletionSource>. 这使得可以等到 Task 完成(TaskCompletionSource 设置结果)然后继续处理结果。结果集由单独的单线程持续读取来自 tcp 流的响应并通过 id 映射它们。

在 F# 中,使用异步而不是任务非常漂亮,所以我看到如何将响应映射到正确请求的方式是存储Dictionary<id, response -> unit> 或者我只能为 MailboxProcessor 提供 1 条消息,Send request并且不将写入请求与读取响应分开。

是否有任何其他类似于 TaskCompletionSource 但用于异步的方式,所以我可以:

// instead of
async {
  do! send request
  sharedDictionary.Add(request.id, fun resp -> () (*do something with this response*) )
  read() }

// do something like
async {
  do! send request
  let! response = read request.id
  (*do something with this response*) }
4

0 回答 0