如何检测 PipeReader 何时到达数据源的末端(管道末端)?
How to detect when a PipeReader has reached the end of the data source (end of pipe)?
我们可以调用 ReadAsync() 并检查读取字节的缓冲区...
PipeReader reader = ...;
ReadResult readResult = await reader.ReadAsync();
ReadOnlySequence<byte> buffer = readResult.Buffer;
long availableBytes = buffer.Length
如果在调用 ReadAsync 之前长度没有增加,是否表示管道结束(没有更多字节要读取)?如果不是那么检测 'end of pipe' 的正确方法是什么?
我们可以像这样表示缓冲区中字节的消耗:
reader.AdvanceTo(count);
然后检查是否有任何未使用的字节,或者是否有可能提供未来的字节(即生产者尚未发出停止向管道添加新字节的信号)
readResult.IsCompleted
但是如果我在缓冲区中寻找一个序列(或多个序列)并在使用它之前等待一个完整的序列,那么 IsComplete 似乎仍然为假,即使缓冲区包含所有可用字节,并且生产者已发出完成信号。
谢谢。
.IsCompleted
确实表示管道的末端,在套接字等意义上 closed (与打开但没有更多数据权相反)现在);我预计这里发生的是你:
- 正在获取读取缓冲区
- 正在读取整个缓冲区以查找序列,但没有找到
- 因此处理零字节
- 因此说
.AdvanceTo(zero)
AdvanceTo
有一个重要的第二个重载 - 你不应该只告诉它你 消耗了什么;你应该告诉它你检查的内容,在这种情况下可能是:一切;这样做可以避免您陷入热循环,一遍又一遍地解析相同的不完整帧。例如,我的一个读取循环看起来像(简化):
while (true)
{
var readResult = await input.ReadAsync();
var buffer = readResult.Buffer;
int handled = TryConsume(ref buffer); // note: this **changes** buffer, slicing (Slice)
// data from the start; when TryConsume exits, it will contain everything
// that is *left*, but we will have effectively examined all of it; we will
// have consumed any complete frames that we can from it
// advance the pipe
input.AdvanceTo(buffer.Start, buffer.End);
// exit if we aren't making progress, and nothing else will be forthcoming
if (handled == 0 && readResult.IsCompleted)
{
break; // no more data, or trailing incomplete messages
}
}
我们可以调用 ReadAsync() 并检查读取字节的缓冲区...
PipeReader reader = ...;
ReadResult readResult = await reader.ReadAsync();
ReadOnlySequence<byte> buffer = readResult.Buffer;
long availableBytes = buffer.Length
如果在调用 ReadAsync 之前长度没有增加,是否表示管道结束(没有更多字节要读取)?如果不是那么检测 'end of pipe' 的正确方法是什么?
我们可以像这样表示缓冲区中字节的消耗:
reader.AdvanceTo(count);
然后检查是否有任何未使用的字节,或者是否有可能提供未来的字节(即生产者尚未发出停止向管道添加新字节的信号)
readResult.IsCompleted
但是如果我在缓冲区中寻找一个序列(或多个序列)并在使用它之前等待一个完整的序列,那么 IsComplete 似乎仍然为假,即使缓冲区包含所有可用字节,并且生产者已发出完成信号。
谢谢。
.IsCompleted
确实表示管道的末端,在套接字等意义上 closed (与打开但没有更多数据权相反)现在);我预计这里发生的是你:
- 正在获取读取缓冲区
- 正在读取整个缓冲区以查找序列,但没有找到
- 因此处理零字节
- 因此说
.AdvanceTo(zero)
AdvanceTo
有一个重要的第二个重载 - 你不应该只告诉它你 消耗了什么;你应该告诉它你检查的内容,在这种情况下可能是:一切;这样做可以避免您陷入热循环,一遍又一遍地解析相同的不完整帧。例如,我的一个读取循环看起来像(简化):
while (true)
{
var readResult = await input.ReadAsync();
var buffer = readResult.Buffer;
int handled = TryConsume(ref buffer); // note: this **changes** buffer, slicing (Slice)
// data from the start; when TryConsume exits, it will contain everything
// that is *left*, but we will have effectively examined all of it; we will
// have consumed any complete frames that we can from it
// advance the pipe
input.AdvanceTo(buffer.Start, buffer.End);
// exit if we aren't making progress, and nothing else will be forthcoming
if (handled == 0 && readResult.IsCompleted)
{
break; // no more data, or trailing incomplete messages
}
}