Настройка длины буфера для чтения небольших данных из NetworkStream - PullRequest
4 голосов
/ 25 ноября 2011

Как правильно настроить bufferSize при чтении небольших данных из TcpClient / NetworkStrem? Если 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);
    }
    

1 Ответ

2 голосов
/ 26 ноября 2011

Похоже, установка ReadTimeout для значений, таких как 1000, 2000 не влияет на блокировку.

Msdn говорит, что ReadTimeout не действует при использовании асинхронного BeginRead метода.

Гарантирует ли установка bufferSize равным 1, что блоков не будет?

Нет, причины нет. Если по соединению не отправлено ни одного байта, вызов Read блокируется независимо от размера буфера.

Будет ли влияние на производительность очень плохим?

Полагаю, вы говорите о 1-байтовом буфере здесь. Это зависит от количества и частоты данных, которые вы получаете, и от того, какой код вы выполняете на EndRead. При обработке потока с высокой пропускной способностью воздействие может быть значительным. При получении данных вы должны попытаться посмотреть на ваш процессор.

Я не совсем уверен, чего вы хотите достичь, соответственно, каково ваше беспокойство по поводу блокировки.

Когда вы запускаете Receive (или Networkstream.Read) с буфером, скажем, 1024 байта, и вы получаете 10 байтов на сокете, вызов Read вернет эти 10 байтов после небольшой задержки, но не будет блокироваться, пока весь буфер заполнен.

Есть ли другой способ сделать блокировку короткой?

Что вы имеете в виду под short . Как я уже сказал, даже при большом буфере чтение не будет бесконечно блокироваться при получении небольших объемов данных.

(NoDelay = true не работает)

Это совершенно другая история , но было бы интересно установить ее на true на стороне отправителей (если вы тоже это контролируете).

Если установлено значение false (по умолчанию), оно объединит небольшие отправляемые данные в более крупные, чтобы уменьшить накладные расходы одного tcp-пакета (заголовок 40 байтов).

EDIT

Я имею в виду NetworkStream.BeginRead для немедленного возврата, если данных нет.

Как насчет использования stream.DataAvailable? Он должен возвращать false, когда нет данных.

Кроме того, при использовании асинхронного шаблона не ожидается ли поведение, которое вызовы будут блокировать, пока не будет что-то делать? В противном случае вы получите активный опрос в занятом цикле.

Когда буфер большой, иногда он ждет 60 секунд для возврата (когда он не полностью заполнен или заполнен до некоторой величины)

Хм, не могу в это поверить. Какие данные вы отправляете по каналу? 1 байт каждую минуту? 1000 байт в секунду?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...