最近在看node.js, 介绍中提到node是异步io的方式实现, 性能比同步阻塞io的更好. 对于一个request而言, 如果我们依赖io的结果, 异步io和同步阻塞io都是要等到io完成才能继续执行. 而同步阻塞io, 一旦阻塞就不会在获得cpu时间片, 那么为什么异步的性能更好呢?
这个问题之前在做Servlet AIO优化的时候就没想太明白. 现在回想起来tomcat这类server的BIO并发数是有瓶颈的, 即便是空跑也只能到1000个并发量级, 而Nginx可以做到C10k. 问题其实就出在线程的数量上面.
同步io模型需要对每个请求创建一个线程, 在io时, 线程被block住, 虽然不消耗cpu, 但线程本身是有内存开销的. 虽然创建少量线程的开销在现代操作系统中很低, 但是这个量到达10k的并发之后, 这个量就很大了. 其次, 活跃线程的context switch开销也会消耗额外的cpu资源.
而异步模型只创建固定的线程, (一般等于cpu核数), 处理并发的请求, 在io的地方用操作系统提供的异步io实现, 避免了线程频繁创建, 销毁和context switch的开销. 因此更快. 这里的快是指吞吐量更大, cpu资源的更有效利用.
有一点也需要注意, 就是从request进来到完成, 应用内各个节点和调用流程都要支持异步io调用, 否则一个节点不支持, 就退化成多线程的解决方式. 比如Servlet -> JDK -> 操作系统, 每个环节都要做异步的支持.
最后说下同步, 异步, 阻塞, 非阻塞几点的区别.
同步异步是在调用的角度上面看, 同步是调用方主动完成操作. 而异步是在调用完成后, 被调用方执行回调完成操作.
阻塞非阻塞是指执行线程有没有停止执行, 阻塞是线程block住不再获得cpu时间片, 非阻塞是指线程还是active的, 可以继续获得时间片, 执行其他任务.