🚀 ​深入理解异步I/O与线程行为:从文件读取到IOCP线程池

57 阅读2分钟

🔍 ​I/O操作的本质认知

​IO读取文件的时候和你的应用程序已经没什么关系了 已经是系统级的事情了 和你的进程线程无关 并且~ 磁盘IO的时候不占用CPU了

在异步读取的时候,线程在干啥? 
如果你定义 var task = syncFun(); 的话 线程会继续执行直到执行到await部分 
如果此时任务已经完成了那么线程继续执行[每个task都有一个状态字段 isCompleted]
如果没有执行完成这个时候线程会回到线程池变成空闲态, 之后等待线程池分配任务队列的任务, 如果分配到了任务会进入就绪态 然后等待CPU的时间片

如果是同步读取 线程会一直保持阻塞状态, 当然此时只是占用线程不占用CPU, 因为CPU只会把时间片分配给就绪态的线程
我们平时定义的 OnFinished() , 也就是 ContinueWith 其实就是在方法执行完成之后呢 
我们先把 OnFinished 的任务打包放到线程池, 之后把后续的方法打包进入线程池
ReadFileAsync("a.txt", a => {
    ReadFileAsync("b.txt", b => {
        Process(a + b); // 嵌套越来越深
    });
});
一样的 可以避免回调地狱
ReadFileAsync("a.txt")
    .ContinueWith(taskA => ReadFileAsync("b.txt"))
    .ContinueWith(taskB => Process(taskB.Result));
!!! 重点说明 IO多路复用 比如说select,epoll等相关以及IOCP都是指的系统内核级的内容
最后介绍一下IOCP线程在await与ContinueWith中的区别,再说一遍IOCP的线程的数量是和CPU数量差不多的
这里需要介绍的是IOCP与IOCP线程分别是系统级别和用户级别的不同的内容
内核级别的IOCP在任务完成的时候会通知给IOCP线程
如果是await的话,IOCP线程会直接去做这件事,如果挤压超过一定时间会扩容,扩容达到上限会交给其他其他线程,通过任务队列[不会发生基本]
如果是ContinueWith那么IOCP线程会把注册的委托封装之后丢到线程池中