如何利用Memory<T>实现非连续缓冲区的连续视图?Socket通信场景
关于Memory表示非连续缓冲区及Socket通信场景的解决方案
首先明确:Memory
针对你的Socket通信场景,提供以下可行方案:
方案一:复制非连续数据到连续Memory(简单但有开销)
如果可以接受内存复制的开销,将非连续的ArraySegment<byte>集合合并到一个连续数组,再包装为Memory<byte>:
var segments = new List<ArraySegment<byte>> { /* 你的非连续缓冲区 */ }; int totalLength = segments.Sum(s => s.Count); byte[] contiguousBuffer = new byte[totalLength]; int offset = 0; foreach (var segment in segments) { Buffer.BlockCopy(segment.Array, segment.Offset, contiguousBuffer, offset, segment.Count); offset += segment.Count; } Memory<byte> contiguousMemory = contiguousBuffer;
此方案适合数据量不大的场景,后续可通过预分配连续缓冲区优化复制开销。
方案二:为IList<ArraySegment>补充CancellationToken支持
若不想复制内存,保留IList<ArraySegment<byte>>的同时,可通过以下方式添加CancellationToken支持(.NET 5+):
using var cts = new CancellationTokenSource(/* 按需设置取消逻辑 */); SocketAsyncEventArgs args = new SocketAsyncEventArgs(); args.BufferList = segments; // 绑定取消令牌 cts.Token.Register(() => args.CancelAsync()); // 执行异步操作 await socket.SendAsync(args, cts.Token);
或直接使用任务的WaitAsync方法:
Task sendTask = socket.SendAsync(segments, SocketFlags.None); await sendTask.WaitAsync(cts.Token);
方案三:自定义MemoryManager(不推荐)
若必须用Memory<T>且避免复制,需自定义MemoryManager<T>,但此方式需要处理大量unsafe代码和内存管理逻辑,且最终仍无法绕过“Span
选型建议
- 若后续优化方向是预分配连续缓冲区,优先选方案一,保留
Memory<T>的灵活性; - 若需避免内存复制,优先选方案二,为
IList<ArraySegment<byte>>补充取消令牌支持,更贴合Socket通信的原生优化。
内容的提问来源于stack exchange,提问作者MDK
相关产品推荐
相关产品推荐

