C# 我们是否应该始终使用PipeWriter.GetMemory>;前进>;脸红我们什么时候使用WriteAsync?

C# 我们是否应该始终使用PipeWriter.GetMemory>;前进>;脸红我们什么时候使用WriteAsync?,c#,.net-core,C#,.net Core,当我遇到以下问题时,我试着寻找这个问题的答案 为什么在前16个有效字节之后读取值为0的16个字节?是因为我们不应该使用WriteAsync吗 示例代码: var r = new Random(); Pipe testPipe = new Pipe(); var Buffer1 = new byte[16]; r.NextBytes(Buffer1); await testPipe.Writer.WriteAsync(Buffer1); testPipe.Writer.Advance(16);

当我遇到以下问题时,我试着寻找这个问题的答案

为什么在前16个有效字节之后读取值为0的16个字节?是因为我们不应该使用WriteAsync吗

示例代码:

var r = new Random();
Pipe testPipe = new Pipe();

var Buffer1 = new byte[16];
r.NextBytes(Buffer1);
await testPipe.Writer.WriteAsync(Buffer1);
testPipe.Writer.Advance(16);
await testPipe.Writer.FlushAsync();

var Buffer2 = new byte[16];
r.NextBytes(Buffer2);
await testPipe.Writer.WriteAsync(Buffer2);
testPipe.Writer.Advance(16);
await testPipe.Writer.FlushAsync();

var result = await testPipe.Reader.ReadAsync();
var Buffer3 = new byte[result.Buffer.Length];
result.Buffer.CopyTo(Buffer3.AsSpan());

我需要的关于这两种方法的所有信息都没有得到全面的报道,而且我也有一个我不理解的问题。

简短版

不要在已在内部调用的
WriteAsync
之后调用
Advance
,该函数只应与GetMemory模式一起使用。另外,不要调用FlushAsync,它也已经在内部调用了

var r = new Random();
Pipe testPipe = new Pipe();

var Buffer1 = new byte[16];
r.NextBytes(Buffer1);
await testPipe.Writer.WriteAsync(Buffer1);
//testPipe.Writer.Advance(16);
//await testPipe.Writer.FlushAsync();

var Buffer2 = new byte[16];
r.NextBytes(Buffer2);
await testPipe.Writer.WriteAsync(Buffer2);
//testPipe.Writer.Advance(16);
//await testPipe.Writer.FlushAsync();

var result = await testPipe.Reader.ReadAsync();
var Buffer3 = new byte[result.Buffer.Length];
result.Buffer.CopyTo(Buffer3.AsSpan());
长版本

WriteAsync
已经在内部调用了
Advance

在源代码中,
WriteAsync
在中定义。该函数只调用管道上的内部函数
return\u pipe.WriteAsync(source,cancellationToken)。该函数调用
AdvanceCore
,这是
Advance
的底层实现

它还在内部调用
Flush
,因此在
WriteAsync
之后不需要这样做。
Flush
操作是唯一异步的操作

WriteAsync
的文档目前没有提到这种行为-请参阅

作者将
WriteAsync
的使用称为错误-请参阅。这是因为PipeWriter在内部有效地使用了“GetMemory>Advance>Flush”方法。这意味着您养成了创建内存缓冲区然后将其复制到管道内存中的习惯,这是低效的。(作者没有提到这样一个事实,即有些API仍然不会写入内存,只会写入字节[])

当您拥有自己的byte[]帧时,使用
WriteAsync
可能会更有效,因为编码似乎会依次迭代和重用可用内存块。这可以防止不必要地在池中创建新内存块。该池用于最小化对象的创建和GC,担心GC开销(和内存页缓存成功?)超过几个CPU周期

如果您使用的函数支持
内存
,请使用
PipeWriter.GetMemory
获取大小合适的内存块,然后可以直接写入缓冲区,缓冲区将通过管道转发到读卡器端