c# Overlapped I/O 和 .NET 的异步IO模型
技术百科
畫卷琴夢
发布时间:2026-01-17
浏览: 次 Overlapped I/O 是 Windows 内核异步 I/O 机制,.NET 的 async/await(如 ReadAsync)在 Windows 上底层依赖它,但由运行时自动封装管理;需显式使用 NativeOverlapped 的场景极少,仅限高性能自定义网络栈等互操作需求。
Overlapped I/O 是什么,和 .NET 的 async/await 有什么关系?
Overlapped I/O 是 Windows 内核提供的异步 I/O 基础机制,本质是让 ReadFile/WriteFile 等 API 在发起后立即返回,由系统在 I/O 完成时通过事件、APC 或 I/O 完成端口(IOCP)通知用户。.NET 的 async/await(如 FileStream.ReadAsync、Socket.ReceiveAsync)在 Windows 上底层大量依赖 Overlapped I/O —— 但你几乎不需要直接操作它。
关键点在于:.NET 运行时已封装好 Overlapped 的生命周期管理(分配、重用、回收)、内存 pinning、完成回调调度。手动调用 NativeOverlapped 或 ThreadPool.BindHandle 属于高级互操作场景,比如实现自定义高性能网络栈、对接非托管库、或绕过 .NET 的 FileStream 缓冲逻辑。
什么时候必须自己用 NativeOverlapped?
极少数情况需要显式控制 Overlapped 结构体,典型包括:
- 调用 Windows API 如
ReadFile、WSARecv等原生异步函数 - 复用同一块 native buffer 和 Overlapped 实例(避免 GC 压力),例如高吞吐服务器中固定大小的接收缓冲池
- 需要精确控制 completion key、APC 函数或与 IOCP 手动绑定
此时要特别注意:NativeOverlapped 必须 pin 住(用 GCHandle.Alloc(..., GCHandleType.Pinned)),且其内存布局需严格匹配 Windows 的 OVERLAPPED 结构;错误的偏移或未初始化字段会导致 ERROR_INVALID_PARAMETER 或静默失败。
FileStream.ReadAsync 底层真的用了 Overlapped 吗?
在 Windows 上,只要构造 FileStream 时传入了 FileOptions.Asynchronous(或使用 new FileStream(path, FileMo),.NET 就会启用内核 Overlapped I/O 模式。否则,即使调用 
ReadAsync,运行时也会退化为同步读 + 线程池线程模拟异步(即 “thread-pool fake async”)。
验证方式很简单:
var fs = new FileStream("test.dat", FileMode.Open, FileAccess.Read, FileShare.None, 4096, FileOptions.Asynchronous);
// 此时 ReadAsync 走真正的 Overlapped I/O
await fs.ReadAsync(buffer, CancellationToken.None);
漏掉 FileOptions.Asynchronous 是最常见性能陷阱 —— 表面是 async 方法,实际阻塞线程池线程,尤其在大文件随机读时放大延迟。
Socket 异步模型:Begin/End vs SocketAsyncEventArgs vs ValueTask
.NET 的 Socket 类提供了三层异步支持:
-
BeginReceive/EndReceive:基于Overlapped+ APC,兼容老代码,但每次调用都 new 委托和状态对象,GC 开销大 -
SocketAsyncEventArgs:可重用的对象池模式,内部持有NativeOverlapped*和 pinned buffer,性能最优,适合高频短连接场景 -
ReceiveAsync(返回ValueTask):现代推荐方式,底层仍走 IOCP,但由运行时自动管理 Overlapped 和 buffer 生命周期;注意它要求 socket 已启用IOControl(IOControlCode.EnableCircularQueues, ...)(.NET 5+ 默认开启)
混用这三者可能引发竞争:比如一个 SocketAsyncEventArgs 正在挂起等待时,又调用 ReceiveAsync,会导致 InvalidOperationException:“The I/O operation has been aborted because of either a thread exit or an application request.”
Overlapped I/O 的复杂性全藏在细节里:buffer pinning 是否持续、completion callback 在哪个线程执行、IOCP 关联是否正确、native handle 是否被提前关闭。.NET 的 async/await 把这些压平了,但压不平的是你对“真正异步”的理解边界 —— 一旦离开托管抽象,就得亲手处理每个 NativeOverlapped 的 EventHandle 和 InternalHigh 字段。
# ai
# 的是
# 就会
# 用了
# 也会
# windows
# 不需要
# 你对
# 自定义
# 什么时候
# app
# 很简单
# win
# 端口
# 对象
# int
# stream
# c#
# FileStream
# 委托
# .net
# access
# 线程
# 栈
# 异步
# 事件
# 封装
# 结构体
# Thread
# 高性能
相关栏目:
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
AI推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
SEO优化<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
技术百科<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
谷歌推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
百度推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
网络营销<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
案例网站<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
精选文章<?muma echo $count; ?>
】
相关推荐
- Win11怎么检查TPM2.0模块_Windows
- Win11怎么关闭应用权限_Windows11相机
- MAC的“接续互通”功能无法使用怎么办_MAC检查
- mac怎么安装pip_MAC Python pip
- Win10如何更改网络连接_Windows10以太
- Drupal 中 HTML 链接被双重转义导致渲染
- Win11怎么开启剪贴板历史记录_Windows1
- 用Python构建微服务架构实践_FastAPI与
- Win11怎么关闭SmartScreen_禁用Wi
- 如何用正则表达式精确匹配最多含一个换行符的起止片段
- Win11怎么关闭VBS安全性_Windows11
- Python随机数生成_random模块说明【指导
- Win11怎么设置开机问候语_自定义Win11锁屏
- 如何在Golang中解压文件_Golang com
- Win10如何卸载Skype_Win10卸载Sky
- 手机php文件怎么变成mp4_安卓苹果打开php转
- Win11资源管理器卡顿怎么办 Win11文件资源
- Windows7如何安装系统镜像_Windows7
- Mac如何整理桌面文件_Mac使用堆栈功能一键整理
- Windows蓝屏错误0x00000018怎么处理
- php高频调试功能有哪些_php常用调试函数与工具
- mac怎么退出id_MAC退出iCloud账号与A
- MySQL 中使用 IF 和 CASE 实现查询字
- php订单日志怎么记录评价_php记录订单评价日志
- php能跑在stm32上吗_php在stm32微控
- Win11怎么退出微软账户_切换Win11为本地账
- 如何在Golang中写入XML文件_生成符合规范的
- Windows10如何更改系统字体大小_Win10
- Drupal 中渲染节点时出现 HTML 标签嵌套
- php打包exe后无法读取环境变量_变量配置方法【
- 如何高效删除 NumPy 二维数组中所有元素相同的
- Mac如何彻底清理浏览器缓存?(Safari与Ch
- php485读数据时阻塞怎么办_php485非阻塞
- Python 模块的 __name__ 属性如何由
- php中作用域操作符能访问私有静态属性吗_访问权限
- php和redis连接超时怎么办_phpredis
- Win11怎么关闭透明效果_Windows11辅助
- Win11怎么设置ip地址_Windows 11手
- 如何使用Golang操作指针变量_Golang解引
- Win11怎么设置开机自动连接宽带_Windows
- Win11应用商店下载慢怎么办 Win11更改DN
- Windows10系统怎么查看防火墙状态_Win1
- 电脑无法识别U盘怎么办 Windows磁盘管理与驱
- Win11怎么设置屏保时间_调整Win11屏幕保护
- php订单日志怎么记录发货_php记录订单发货操作
- 手机php怎么转mp4_手机端php文件转mp4a
- Win11怎么打开旧版计算器_Win11恢复传统计
- php下载安装后memory_limit怎么设置_
- Dapper的Execute方法的返回值是什么意思
- 如何优化Golang程序CPU性能_Golang

QQ客服