用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/rudironsoni/Synaxis --skill dotnet-io-pipelines命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
AI-powered wiki generation for code repositories with commands, agents, and skills
Routes .NET/C# work to domain skills. Loads coding-standards for code paths.
Skill manifest management for dotnet-agent-harness. Tracks skill dependencies, conflicts, version compatibility, and provides validation and resolution tools. Triggers on: skill manifest, dependency resolution, skill compatibility, version conflicts, build manifest, validate dependencies.
基于 SOC 职业分类
正在显示 SKILL.md
| name | dotnet-io-pipelines |
| description | Builds high-perf network I/O. PipeReader/PipeWriter, backpressure, protocol parsers, Kestrel. |
High-performance I/O patterns using System.IO.Pipelines. Covers PipeReader, PipeWriter, backpressure management,
protocol parser implementation, and Kestrel integration. Pipelines solve the classic problems of buffer management,
incomplete reads, and memory copying that plague traditional stream-based network code.
Cross-references: [skill:dotnet-csharp-async-patterns] for async patterns used in pipeline loops, [skill:dotnet-performance-patterns] for Span/Memory optimization techniques, [skill:dotnet-file-io] for file-based I/O patterns (FileStream, RandomAccess, MemoryMappedFile).
Traditional Stream-based I/O forces developers to manage buffers manually, handle partial reads, and copy data between
buffers. System.IO.Pipelines solves these problems:
| Problem | Stream Approach | Pipeline Approach |
|---|---|---|
| Buffer management | Allocate byte[], resize manually | Automatic pooled buffer management |
| Partial reads | Track position, concatenate fragments | ReadResult with SequencePosition bookmarks |
| Backpressure | None -- writer can outpace reader | Built-in pause/resume thresholds |
| Memory copies | Copy between buffers at each layer | Zero-copy slicing with ReadOnlySequence<byte> |
| Lifetime management | Manual byte[] lifecycle | Pooled memory returned on AdvanceTo |
The Pipe class connects a PipeWriter (producer) and a PipeReader (consumer) with an internal buffer pool, flow
control, and completion signaling.
// Create a pipe with default options (uses ArrayPool internally)
var pipe = new Pipe();
PipeWriter writer = pipe.Writer; // Producer side
PipeReader reader = pipe.Reader; // Consumer side
```text
### PipeWriter -- Producing Data
```csharp
async Task FillPipeAsync(Stream source, PipeWriter writer,
CancellationToken ct)
{
const int minimumBufferSize = 512;
while (true)
{
// Request a buffer from the pipe's memory pool
Memory<byte> memory = writer.GetMemory(minimumBufferSize);
int bytesRead = await source.ReadAsync(memory, ct);
if (bytesRead == 0)
break; // End of stream
// Tell the pipe how many bytes were written
writer.Advance(bytesRead);
// Flush makes data available to the reader.
// FlushAsync may pause here if the reader is slow (backpressure).
FlushResult result = await writer.FlushAsync(ct);
if (result.IsCompleted)
break; // Reader stopped consuming
}
// Signal completion -- reader will see IsCompleted = true
await writer.CompleteAsync();
}
```text
**Critical rules:**
- Call `GetMemory` or `GetSpan` before writing -- never write to a previously obtained buffer after `Advance`
- Call `Advance` with the exact number of bytes written
- Call `FlushAsync` to make data available to the reader and to respect backpressure
### PipeReader -- Consuming Data
```csharp
Task ()
{
()
{
ReadResult result = reader.ReadAsync(ct);
ReadOnlySequence<> buffer = result.Buffer;
(TryParseMessage( buffer, message))
{
ProcessMessageAsync(message, ct);
}
reader.AdvanceTo(buffer.Start, buffer.End);
(result.IsCompleted)
;
}
reader.CompleteAsync();
}
```text
**Critical rules:**
- Always call `AdvanceTo` after `ReadAsync` -- failing to so leaks memory
- Pass both `consumed` `examined` positions: `consumed` frees memory, `examined` prevents busy-wait the buffer
has been scanned but does contain a complete message
- Never access `ReadResult.Buffer` after calling `AdvanceTo` -- the memory may be recycled
---
Backpressure prevents fast producers overwhelming slow consumers. The pipe pauses the writer unread data
exceeds a threshold.
```csharp
pipe = Pipe( PipeOptions(
pauseWriterThreshold: * ,
resumeWriterThreshold: * ,
minimumSegmentSize: ,
useSynchronizationContext: ));
```text
| Option | Default | Purpose |
| --------------------------- | ------- | ------------------------------------------------------ |
| `PauseWriterThreshold` | , | `FlushAsync` pauses unread bytes exceed |
| `ResumeWriterThreshold` | , | `FlushAsync` resumes unread bytes drop below |
| `MinimumSegmentSize` | , | Minimum buffer segment allocation size |
| `UseSynchronizationContext` | `` | Set `` server code to avoid context captures |
Writer calls `FlushAsync` after `Advance`
{
payload = ;
(buffer.Length < )
;
length;
(buffer.FirstSpan.Length >= )
{
length = BinaryPrimitives.ReadInt32BigEndian(buffer.FirstSpan);
}
{
Span<> lengthBytes = [];
buffer.Slice(, ).CopyTo(lengthBytes);
length = BinaryPrimitives.ReadInt32BigEndian(lengthBytes);
}
(length < || length > _048_576)
ProtocolViolationException(
);
totalLength = + length;
(buffer.Length < totalLength)
;
payload = buffer.Slice(, length);
buffer = buffer.Slice(totalLength);
;
}
```text
```
{
SequencePosition? position = buffer.PositionOf(());
(position )
{
line = ;
;
}
line = buffer.Slice(, position.Value);
buffer = buffer.Slice(buffer.GetPosition(, position.Value));
;
}
```text
`ReadOnlySequence<>` may span multiple non-contiguous memory segments. Handle both paths:
```
{
(sequence.IsSingleSegment)
{
Encoding.UTF8.GetString(sequence.FirstSpan);
}
length = ()sequence.Length;
[] rented = ArrayPool<>.Shared.Rent(length);
{
sequence.CopyTo(rented);
Encoding.UTF8.GetString(rented, , length);
}
{
ArrayPool<>.Shared.Return(rented);
}
}
```text
---
Bridge `System.IO.Pipelines` existing `Stream`-based APIs `PipeReader.Create` `PipeWriter.Create`.
```csharp
networkStream = tcpClient.GetStream();
reader = PipeReader.Create(networkStream, StreamPipeReaderOptions(
bufferSize: ,
minimumReadSize: ,
leaveOpen: ));
{
ProcessProtocolAsync(reader, cancellationToken);
}
{
reader.CompleteAsync();
}
```text
```csharp
writer = PipeWriter.Create(networkStream, StreamPipeWriterOptions(
minimumBufferSize: ,
leaveOpen: ));
{
WriteResponseAsync(writer, response, cancellationToken);
}
{
writer.CompleteAsync();
}
```text
---
ASP.NET Core