每个请求创建一个线程,同样适用非阻塞IO操作
线程数目固定,可以在程序启动的时候设置,不会频繁的创建与销毁可以方便地在线程间调配负载IO事件发生的线程时固定的,同一个TCP连接不必考虑事件的并发使用线程池,同样使用非阻塞IO操作
使用非阻塞IO +IO复用
Leader/Follower等高级模式
推荐使用的模式:one loop per thread + thread pool , 即每个IO线程里面有一个事件循环(Reactor)用于处理读写或定时事件,线程池用来做计算,具体可以是任务队或生产者消费者队列
TCP长连接与短连接?参考
短连接是指通信双方有数据交互时,就建立一个TCP连接,数据发送完成后,则断开此TCP连接(管理起来比较简单,存在的连接都是有用的连接,不需要额外的控制手段连接——>数据传输——>关闭连接
所谓长连接,指在一个TCP连接上可以连续发送多个数据包,在TCP连接保持期间,如果没有数据包发送,需要双方发检测包以维持此连接,一般需要自己做在线维持(不发生RST包和四次挥手)。
连接→数据传输→保持连接(心跳)→数据传输→保持连接(心跳)→……→关闭连接(一个TCP连接通道多个读写通信);
这就要求长连接在没有数据通信时,定时发送数据包(心跳),以维持连接状态
两者的应用场景
长连接多用于操作频繁(读写),点对点通信,而且连接数不能太大,如数据库的连接而像WEB网站的http服务一般都用短链接(http1.0只支持短连接,1.1keep alive 带时间,操作次数限制的长连接),因为长连接对于服务端来说会耗费一定的资源,而像WEB网站这么频繁的成千上万甚至上亿客户端的连接用短连接会更省一些资源,如果用长连接,而且同时有成千上万的用户,如果每个用户都占用一个连接的话,那可想而知吧。所以并发量大,但每个用户无需频繁操作情况下需用短连好;TCP长连接的好处
容易定位分布式系统中的服务之间的依赖关系,运行netstat -tpna | grep :port 就能列出到某服务端的客户端地址通过接受和发送队列的长度也比较容易定位网络或程序故障一台机器上可以创建远远高于CPU数目的线程,一个线程只处理一个TCP连接(甚至半个)。通常使用阻塞IO(有返回才继续进行)
只能创建与CPU数目相当的线程,这是一个线程要处理多个TCP连接上的IO,通常使用非阻塞IO和IO复用
本书只考虑后面一种模式
多线程服务程序中的线程大致分为3类
IO线程,这类线程的主循环是IO复用,阻塞地等待在select/poll/epoll_wait系统调用上面
计算线程,这类线程的主循环是blocking queue,阻塞等待条件变量上。一般位于线程池中。一般不涉及任何IO,一般要避免任何阻塞操作
第三方库所在的线程,比如logging,database connection
服务器程序一般不会频繁的启动和终止线程,只在启动时调用,在运行期间是不调用的
Linux能同时启动多少个线程
对于32位系统,一个进程的地址空间是4GB,其中用户态能访问3G作用,一个线程的默认栈大小是10MB,故一个进程可以同时启动300个线程
对于64位系统可以大大增加
多线程能提高并发度么?
如果是并发连接数则不能,由上一问可知,并发连接数上限是300远低于基于事件的单线程程序所能轻松达到的并发连接数(几千上万)
one loop per thread 不逊于单线程程序,单个事件循环处理1万个连接并不罕见,一个多事件循环的多线程程序应该能轻松支持5万并发连接
总结:thread per connection 不适合高并发场合。one loop per thread 的并发度足够大,与CPU数目成正比
多线程编程能提高吞吐量么?
对于计算密集型服务器,不能
多线程能降低响应时间么?
设计合理,充分利用多核资源,可以,在突发请求时尤为明显
多线程程序如何让IO和计算相互重叠,降低时延
把IO操作通过BlockingQueue交给别的线程去做,自己不必等待
为啥第三方库往往需要自己的线程
什么是线程池大小的阻抗匹配原则
T = C/P;,线程池完全是计算P=1,线程池一半是计算,一半在等待IO,则P=0.5;,P<0.2时,不适用
除了Reactor + thread pool 还有什么非阻塞编程思想
有,Proctor.如果一次请求响应要和别的进程多次打交道,那么该模型能做到更高的并发度,代价是代码变得支离破碎。
多线程的进程和单线程的多进程如何取舍?
如果工作集较大,就要多线程,避免cpu cache换入换出,影响性能,否则就要单线程多进程