最近在读 shadowsocks 的源码,有一些疑惑。 shadowsocks 每次通过 epoll 监听到新连接之后,程序都会阻塞一段时间去执行 on_remote_read() 或 on_remote_write() 来传输数据,数据传输完毕之后才会再次调用 epoll 并 accept 新的 socket 连接,当连接达到一定数量之后,会出现高延迟、低效率的情况啊
# 在知乎上问了这个问题,没人理只好来 SegmentFault 啦~
光阴似箭催人老,日月如移越少年。
因为这个过程是高CPU、高内存的操作,而非高硬盘IO的操作,也就是说,这个过程考验的是CPU性能。而我们知道,计算机了没有真正的多进程或是多线程,都是通过CPU调度模拟出来的。那么对于高CPU的操作,最好就是用单进程或者单线程的方法来处理(多核心可考虑增加),这样才是最高效的办法,因为这样避免了线程或进程来回切换带来的消耗。
这块可以参考Nginx的架构,Nginx的高负载也是在单进程中完成的。
CPython的多线程不是“真正”的多线程(详见 GIL),不换语言的话,解决方法是多进程,前面架一个负载均衡(haproxy之类的)。
处理并发连接有多种模型。多线程是一种,epoll所代表的non-blocking I/O + multiplexing也是一种。只要用得对,新连接进来之后的read/write就不会阻塞哪怕是很小一段时间。
早些年的老司机都读过Dan Kegel的The C10K Problem,里面对各种并发处理模型有讲解。如果英文还过得去的话还是建议你读读。哦对了,如果是学习概念,不涉及实际系统上为了处理大并发量而做的各种技巧性增强,那么Richard Stevens的《Unix网络编程》里面讲得更清楚,中译版也易读一些。
因为这个过程是高CPU、高内存的操作,而非高硬盘IO的操作,也就是说,这个过程考验的是CPU性能。而我们知道,计算机了没有真正的多进程或是多线程,都是通过CPU调度模拟出来的。那么对于高CPU的操作,最好就是用单进程或者单线程的方法来处理(多核心可考虑增加),这样才是最高效的办法,因为这样避免了线程或进程来回切换带来的消耗。
这块可以参考Nginx的架构,Nginx的高负载也是在单进程中完成的。
CPython的多线程不是“真正”的多线程(详见 GIL),不换语言的话,解决方法是多进程,前面架一个负载均衡(haproxy之类的)。
处理并发连接有多种模型。多线程是一种,epoll所代表的non-blocking I/O + multiplexing也是一种。只要用得对,新连接进来之后的read/write就不会阻塞哪怕是很小一段时间。
早些年的老司机都读过Dan Kegel的The C10K Problem,里面对各种并发处理模型有讲解。如果英文还过得去的话还是建议你读读。哦对了,如果是学习概念,不涉及实际系统上为了处理大并发量而做的各种技巧性增强,那么Richard Stevens的《Unix网络编程》里面讲得更清楚,中译版也易读一些。