调优从NetworkStream读取小数据的缓冲区长度



如何在从TcpClient/networkstream读取小数据时微调bufferSize ?如果bufferSize很大,比如1024,4096,则Read/BeginRead块。如果我将bufferSize设置为16,32,它可以不阻塞地工作。

  • 设置bufferSize为1保证不会有任何块吗?性能影响会非常糟糕吗?
  • 看起来像将ReadTimeout设置为1000,2000这样的值对阻塞没有影响。还有其他方法可以阻塞吗是短的吗?(NoDelay = true不起作用)

    public static IObservable<byte[]> AsyncReadChunk(this Stream stream, int bufferSize)
    {
        var buffer = new byte[bufferSize];
        return Observable.FromAsyncPattern<byte[], int, int, int>(stream.BeginRead, stream.EndRead)(buffer, 0, bufferSize)
            .Select(cbRead =>
                        {
                            var dataChunk = new byte[cbRead];
                            Buffer.BlockCopy(buffer, 0, dataChunk, 0, cbRead);
                            return dataChunk;
                        });
    }
    public static IObservable<byte[]> AsyncRead(this NetworkStream stream, int bufferSize)
    {
        return Observable.Defer(() => stream.DataAvailable ? AsyncReadChunk(stream, bufferSize) : Observable.Return(new byte[0]))
            .Repeat()
            .TakeWhile((dataChunk, index) => dataChunk.Length > 0);
    }
    

它看起来像设置ReadTimeout设置为1000,2000对阻塞没有影响。

Msdn说,当使用async BeginRead方法时,ReadTimeout没有影响。

设置bufferSize为1保证不会有任何块吗?

没有,当然没有。当没有一个字节通过连接发送时,无论缓冲区大小如何,Read调用都会阻塞。

性能影响会很糟糕吗?

我猜你说的是1字节缓冲区。这取决于您接收的数据的数量和频率以及您在EndRead上执行的代码。当处理具有高带宽的流时,影响可能很大。当你接收数据时,你必须试着观察你的cpu。

我不太确定你想分别实现什么,你对阻塞的担忧是什么。

当你用1024字节的缓冲区启动Receive(或Networkstream.Read)时,你在套接字上收到10字节,Read调用将在短暂的延迟后返回这10字节,但不会阻塞,直到整个缓冲区被填满。

还有其他方法可以使阻塞缩短吗?

是什么意思?正如我所说,即使有很大的缓冲区,当接收到少量数据时,Read也不会无休止地阻塞。

(NoDelay = true不起作用)

这是一个完全不同的故事,但在您的发送方将其设置为true可能会很有趣(如果您也可以控制它)。

当设置为false(默认)时,它会将发送的小数据块合并为大数据块,以减少一个tcp数据包(40字节报头)的开销。

编辑

我是说NetworkStream。如果没有数据,BeginRead将立即返回。

使用stream.DataAvailable怎么样?当没有数据时,它应该返回false。

此外,当使用异步模式时,它不是预期的行为,调用将阻塞,直到有事情要做?否则,您将在繁忙循环中获得活动轮询。

当缓冲区很大时,它有时会等待60秒返回(当它没有完全填充或填充到一定数量时)

嗯,真不敢相信。你通过信道发送什么样的数据?每分钟1字节?每秒1000字节?

最新更新