IO:程序中使用IO流,需要和操作系统的内核打交道,在Linux内核中,IO会被看做是一个描述符(FD:文件描述符,/SD:网络描述符),这个描述符会指向一个结构体
阻塞IO模型:传统的IO最大的缺点就是它是阻塞的,当某个客户端发送数据过来,当前的线程必须要等该链接将数据全部发送到系统buffer中,然后从系统的buffer空间移动到进程(应用程序)的buffer空间,在这段时间,线程只能傻傻的在等待,资源被严重浪费,一般情况下,一个请求就是一个链接,早起操作系统对线程连接数也有要求,所以,在处理高并发的时候,这个是一个瓶颈问题。
非阻塞IO模型:非阻塞模型主要是线程会轮询检查内核数据是否到来,如果到的话,就 处理,如果没有到的话,就返回,等待下次被轮询检查
IO多路复用模型:多路复用利用到了,Linux系统内核自带的select/poll/epoll技术,主要原理就是,将fd/sd注册给select/poll/epoll系统,阻塞会发生在这些系统上,select/poll/epoll会轮询检查注册在上面的fd的状态,如果就绪,就立即回调。select/poll:它们是顺序轮询fd/sd,而且最大注册数有限制,所以性能不能达到最好。epoll:使用事件驱动的方式进行轮询,最大注册数理论上是操作系统的最大文件句柄数。注意:java的NIO的Selector是基于epoll技术来实现的
select/poll特点:
- 由于在上面注册了很多fd的数据,是一个集合,但是实际上会存在很多空闲链路,但是这种顺序的轮询,会导致效率大幅下降
- 最大注册数有限
epoll特点:
- 它只会针对非空闲链路进行轮询,效率大幅提高
- 最大注册数不受限制,只受限于操作系统的最大文件句柄数
异步IO:用户进程向内核启动一个请求,然后就是内核帮助我们做完所有的事情,接受完数据并从操作系统内核缓冲区拷贝到用户缓冲区。特点是:帮助我们做完,才通知。
网络编程的模式:一般情况是服务端暴漏一个IP和端口地址,监听这个端口的请求,客户端根据这个地址,发送请求,先是进行TCP三次握手链接,然后进行通信。
BIO模型:服务端监听某个端口,有一个Acceptor线程专门监听客户端链接,如果有则创建一个新的线程与之通信,在通信完成之后,将销毁该工作线程。整个过程将创建大量的线程,消耗服务端大量的资源,在并发达到一定的量之后,系统会崩溃。
伪异步IO:本质上是在BIO模型的基础上,服务端加入了一个线程池的概念,客户端连接的请求时,服务端会从线程池中获取一个线程进行处理,但是如果并发量特别大的时候,客户端任务会被加入到队列任务中,长时间客户端没有接受到回复,会认为超时。
线程切换:因为一个处理器同一时刻只能运行一个线程,所以多个线程只能是轮流执行,从执行某一个线程改为执行另一个线程的过程就是线程切换。
频繁切换是指创建了很多个线程,CPU要轮流执行这些线程,因为切换线程需要一定的时间,当线程数量较少时,切换的时间可以忽略不计,而线程数量很多(大约几百个,与物理内存容量有关)时,由于物理内存不足,切换线程需要从虚拟内存中交换数据,所以花费的时间大大增加,导致系统效能降低。
同步:同步就是一个任务的完成需要依赖另外一个任务时,只有等待被依赖的任务完成后,依赖的任务才能算完成,这是一种可靠的任务序列
异步:不需要等待被依赖的任务完成,只是通知被依赖的任务要完成什么工作,依赖的任务也立即执行,只要自己完成了整个任务就算完成了。至于被依赖的任务最终是否真正完成,依赖它的任务无法确定,所以它是不可靠的任务序列。
阻塞:阻塞调用是指调用结果返回之前,当前线程会被挂起,一直处于等待消息通知,不能够执行其他业务。函数只有在得到结果之后才会返回。
非阻塞:非阻塞和阻塞的概念相对应,指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回。虽然表面上看非阻塞的方式可以明显的提高CPU的利用率,但是也带了另外一种后果就是系统的线程切换增加。增加的CPU执行时间能不能补偿系统的切换成本需要好好评估
非阻塞的一种解释:
In JavaScript, almost all I/O is non-blocking. This includes HTTP requests, database operations and disk reads and writes; the single thread of execution asks the runtime to perform an operation, providing a callback function and then moves on to do something else. When the operation has been completed, a message is enqueued along with the provided callback function. At some point in the future, the message is dequeued and the callback fired.
在js中,几乎所有的I/O都是非阻塞(译者注:简单的说就是在读文件或数据库时,程序不暂停等待结果,而是继续执行,等读到了结果后去执行)的.包括HTTP请求,数据库操作还是文件读写.线程执行了一个I/O操作时返回一个回调函数,然后继续执行其他程序.当那个操作完成时,一个携带着回调函数的(完成)消息被加到消息队列,在后来某个点,这个消息出队,相应的回调函数被执行.