是否值得将TcpClient WriteAsync和ReadAsync包装到MailboxProcessor中?

时间:2016-01-30 23:44:27

标签: .net f# asyncsocket mailboxprocessor

问题摘要:

  1. Stream.WriteAsync和Stream.ReadAsync是否相互阻塞,可以完全并行地在2个cpu核心上运行?
  2. 有没有办法通知等待外部源在async {}中通知?
  3. MailboxProcessor作为TcpClient包装器的性能影响是什么?
  4. 一些解释:

    据我所知,Stream.cs异步操作的源代码是同步完成的,而不是完全并行完成(如果你读了一些东西,它会阻止其他读取尝试直到完成,并且还阻止写入attemts,同样以其他方式 - 写入块读取和写入尝试),它不会阻止调用writeAsync / readAsync的线程的唯一好处

    所以我将TcpClient包装到接受

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

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

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

    此外,这是为了向服务器发送请求,以确保响应顺序与收到的请求相同 但我不能依赖Write requestA - &gt; Read responseA阅读正确答案:   tread1:     写请求A.     阅读回复A.   tread2:     写请求B.     阅读回复B

    队列:[&#39;写请求A&#39 ;; &#39;写请求B&#39 ;; &#39;阅读回复B&#39 ;; &#39;阅读回复A&#39;] 这将导致responseA将返回到thread2,而responseB将返回到thread1。

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

    在F#中,使用Async而不是Task非常漂亮,因此我看到如何将响应映射到正确的请求的方式是存储Dictionary<id, response -> unit> 或者我只能为邮箱处理器发送一条消息,例如Send request,并且不会将写请求与读取响应分开。

    还有其他类似于TaskCompletionSource的方法,但是对于Async,我可以这样:

    // 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*) }
    

0 个答案:

没有答案