gpt4 book ai didi

c# - 管道缓冲区保留直到处理完成

转载 作者:行者123 更新时间:2023-12-04 15:18:32 24 4
gpt4 key购买 nike

我正在研究使用管道处理来自网络的二进制消息的可能性。我将处理的二进制消息带有有效负载,最好将有效负载保持为二进制形式。

想法是读出整个消息并创建一个消息片段及其有效负载,一旦消息被完全读取,它将被传递到 channel 链进行处理,处理不会立即进行,可能需要一些时间或稍后执行,目标是不让管道读取器等待直到处理完成,然后一旦消息处理完成,我需要将已处理的缓冲区释放给管道写入器。

现在我当然可以创建一个新的字节数组并复制来自 pipe writer 的数据,但这会破坏 no-copy 的目的吗?所以据我所知,我需要在管道和 channel 之间进行一些缓冲区同步吗?我观察了管道读取器的可用 API (AdvanceTo),它可以告诉管道读取器消耗了什么和检查了什么,但无法解决如何在管道读取方法之外同步。

所以问题是是否有一些技术或示例可以实现这一目标。

最佳答案

TryRead获得的缓冲区/ReadAsync仅在您调用 AdvanceTo 之前有效,期望一旦你这样做了:你报告为消耗的任何东西都可以回收用于其他地方(可以是并行/并发读者)。严格来说:即使您没有报告为消耗的位:一旦您调用了AdvanceTo,您仍然不应该将其视为有效位(虽然在现实中,它们很可能仍然是相同的段——只是:这不是调用者关心的;对于调用者来说,它只在读取和推进之间有效)。

这意味着您明确不能这样做:

while (...)
{
var result = await pipe.ReadAsync();
if (TryIdentifyFrameBoundary(out var frame)) {
BeginProcessingInBackground(frame); // <==== THIS IS A PROBLEM!
reader.AdvanceTo(frame.End, frame.End);
}
else if { // take nothing
reader.AdvanceTo(buffer.Start, buffer.End);
if (result.IsCompleted) break; // that's all folks
}
}

因为“在后台”位,当它触发时,现在可以读取其他人的数据(因为它已经被重用)。

因此:或者您需要将帧内容作为读取循环的一部分进行处理,或者您将不得不复制数据,大多数情况下可能通过使用:

c#
var len = checked ((int)buffer.Length);
var oversized = ArrayPool<byte>.Shared.Rent(len);
buffer.CopyTo(oversized);

并通过oversized到你的后台处理,记住只看第一个 len它的字节。您可以将其作为 ReadOnlyMemory<byte> 传递,但你需要考虑到你之后还想将它返回到数组池中(可能在 finally block 中),并将它作为内存传递会使它变得有点尴尬(但并非不可能,感谢 MemoryMarshal.TryGetArray )。


注意:在管道 API 的早期版本中,有一个引用计数元素,它确实允许您保留缓冲区,但它有一些问题:

  • 它使 API 变得非常复杂
  • 它导致缓冲区泄漏
  • “保留”的含义含糊不清;在它被重用之前是计数吗?还是完全释放

所以该功能被删除了。

关于c# - 管道缓冲区保留直到处理完成,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63848351/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com