目录

之前学习的一些文档:

零拷贝技术 文件传输(读取与发送)中的拷贝与上下文切换 https://www.wolai.com/9ya76io6rbUXFki99avf2L

之前都是纸上谈兵,这次让我们利用这原理来实现queue

零拷贝队列实现文档

本文档详细说明了三种零拷贝队列的实现方式:SendfileQueue、MmapQueue和SpliceQueue。

classDiagram QueueBase <|-- SendfileQueue QueueBase <|-- MmapQueue QueueBase <|-- SpliceQueue class QueueBase { <<abstract>> +~QueueBase() +enqueue(data: char, size: size_t) bool +dequeue(buffer: char, size: size_t) ssize_t } class SendfileQueue { -data_fd_: int -write_pos_: size_t -read_pos_: size_t -max_size_: size_t +SendfileQueue(data_file: string, max_size: size_t) +~SendfileQueue() +enqueue(data: char, size: size_t) bool +dequeue(buffer: char, size: size_t) ssize_t } class MmapQueue { -data_fd_: int -buffer_: char -write_pos_: size_t -read_pos_: size_t -max_size_: size_t +MmapQueue(data_file: string, max_size: size_t) +~MmapQueue() +enqueue(data: char, size: size_t) bool +dequeue(buffer: char, size: size_t) ssize_t } class SpliceQueue { -data_fd_: int -pipe_fds_: int[2] -write_pos_: size_t -read_pos_: size_t -max_size_: size_t +SpliceQueue(data_file: string, max_size: size_t) +~SpliceQueue() +enqueue(data: char, size: size_t) bool +dequeue(buffer: char, size: size_t) ssize_t }

实现流程图

SendfileQueue实现流程

MmapQueue实现流程

flowchart TD subgraph Enqueue E1[开始] --> E2{检查空间} E2 -->|足够| E3[memcpy到映射内存] E2 -->|不足| E4[返回失败] E3 --> E5[更新write_pos] E5 --> E6[返回成功] end subgraph Dequeue D1[开始] --> D2{检查数据} D2 -->|有数据| D3[计算可读取量] D2 -->|无数据| D4[返回0] D3 --> D5[memcpy到buffer] D5 --> D6[更新read_pos] D6 --> D7[返回读取字节数] end

flowchart TD subgraph Enqueue E1[开始] --> E2{检查空间} E2 -->|足够| E3[分批处理] E2 -->|不足| E4[返回失败] E3 --> E5[write写入管道] E5 --> E6[splice到文件] E6 --> E7[更新write_pos] E7 --> E8[返回成功] end subgraph Dequeue D1[开始] --> D2{检查数据} D2 -->|有数据| D3[分批处理] D2 -->|无数据| D4[返回0] D3 --> D5[splice到管道] D5 --> D6[read读取到buffer] D6 --> D7[更新read_pos] D7 --> D8[返回读取字节数] end

时序图

SendfileQueue操作时序

MmapQueue操作时序

sequenceDiagram participant C as Client participant Q as MmapQueue participant M as MappedMemory participant F as DataFile %% 初始化 C->>+Q: 构造函数 Q->>+F: open文件 Q->>F: ftruncate设置大小 Q->>+M: mmap映射文件 M-->>-Q: 返回映射内存 F-->>-Q: 返回文件描述符 Q-->>-C: 返回实例 %% Enqueue操作 C->>+Q: enqueue(data, size) Q->>+M: memcpy数据 M-->>-Q: 复制完成 Q-->>-C: success/failure %% Dequeue操作 C->>+Q: dequeue(buffer, size) Q->>+M: memcpy到buffer M-->>-Q: 复制完成 Q-->>-C: 返回数据/错误

sequenceDiagram participant C as Client participant Q as SpliceQueue participant P as Pipe participant F as DataFile %% Enqueue操作 C->>+Q: enqueue(data, size) loop 每个64KB批次 Q->>+P: write写入批次 P-->>-Q: 写入完成 Q->>+F: splice从管道到文件 F-->>-Q: splice完成 end Q-->>-C: success/failure %% Dequeue操作 C->>+Q: dequeue(buffer, size) loop 每个64KB批次 Q->>+F: splice到管道 F-->>-Q: splice完成 Q->>+P: read到buffer P-->>-Q: 读取完成 end Q-->>-C: 返回数据/错误

性能特点分析

SendfileQueue

  • 优点
    • 实现简单直观
    • 使用sendfile系统调用避免用户空间拷贝
    • 适合整块数据传输
  • 缺点
    • 需要创建临时文件
    • dequeue操作有额外的文件I/O开销
    • 不适合高频小数据操作

MmapQueue

  • 优点
    • 直接内存操作,速度最快
    • 读写操作都是简单的内存拷贝
    • 适合频繁的读写操作
  • 缺点
    • 占用虚拟内存空间
    • 大文件映射需要注意内存管理
    • 需要处理内存映射失败的情况

SpliceQueue

  • 优点
    • 完全零拷贝,不涉及用户空间
    • 内存占用小
    • 适合大数据流传输
  • 缺点
    • 实现较复杂
    • 需要管理管道缓冲区
    • 分批处理增加了代码复杂度

使用建议

  1. 小数据量、高频访问场景
    • 推荐使用MmapQueue
    • 直接内存操作性能最好
    • 避免系统调用开销
  2. 大数据量、内存受限场景
    • 推荐使用SpliceQueue
    • 避免内存映射的开销
    • 完全零拷贝传输
  3. 简单实现、临时文件可接受场景
    • 推荐使用SendfileQueue
    • 实现简单,易于维护
    • 适合不频繁的大块数据传输

性能测试结果

基于1GB数据量、1MB消息大小的测试结果:

队列类型 入队时间(ms) 出队时间(ms) 总吞吐量(GB/s)
SendfileQueue ~500 ~700 ~1.6
MmapQueue ~500 ~200 ~2.6
SpliceQueue ~600 ~400 ~2.0

注:实际性能可能因硬件配置和系统负载而异。

Starting Zero-Copy Queue Performance Tests
=========================================

Testing Sendfile Queue...
Configuration:
- Queue size: 1024 MB
- Message size: 1024 KB
- Number of messages: 1000
- Total data: 1000 MB

Generating test data...
Starting enqueue test...
Progress: 100%%

Starting dequeue test...
Progress: 100%%

Performance Results:
- Enqueue time: 358ms
- Dequeue time: 777ms
- Total time: 1135ms
- Throughput: 1.72 GB/s
- Messages/sec: 1762


Testing Mmap Queue...
Configuration:
- Queue size: 1024 MB
- Message size: 1024 KB
- Number of messages: 1000
- Total data: 1000 MB

Generating test data...
Starting enqueue test...
Progress: 100%%

Starting dequeue test...
Progress: 100%%

Performance Results:
- Enqueue time: 450ms
- Dequeue time: 271ms
- Total time: 721ms
- Throughput: 2.71 GB/s
- Messages/sec: 2774


Testing Splice Queue...
Configuration:
- Queue size: 1024 MB
- Message size: 1024 KB
- Number of messages: 1000
- Total data: 1000 MB

Generating test data...
Starting enqueue test...
Progress: 100%%

Starting dequeue test...
Progress: 100%%

Performance Results:
- Enqueue time: 398ms
- Dequeue time: 229ms
- Total time: 627ms
- Throughput: 3.12 GB/s
- Messages/sec: 3190

Comments 0

No comments yet.

← More postsThat’s all for now. Thanks for reading.