We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
服务端编程需要构建高性能的 IO 模型,常见的 IO 模型主要有以下四种
同步与异步 用户线程与内核的交互方式;同步是指用户发起 IO 请求后,需要等待或者轮询内核 IO 操作完成后才能继续执行;异步是指用户线程发起 IO 请求后继续执行,当内核操作完成后会通知线程或者调用用户线程注册的回调函数
阻塞与非阻塞 用户线程调用内核 IO 操作的方式;阻塞是指 IO 操作需要彻底完成后才返回到用户空间,而非阻塞是指 IO 操作被调用后立即返回给用户一个状态值
用户线程通过系统调用 read 发起 IO 操作,由用户空间转到内核空间,内核等到数据包到达以后,将接受的数据拷贝到用户空间,完成 read,用户需要等待 read 将 socket 中的数据读取到 buffer 后,才继续处理接收的数据,整个 IO 请求过程中,用户线程是被阻塞的,导致用户发起请求时,不能做任何事情,对 CPU 资源利用不够。
同步非阻塞 io,在同步阻塞 io 的基础上,将 socket 设置为 nonblock,用户线程可以在发起 io 请求后立即返回;socket 是非阻塞的方式,用户线程发起 IO 请求时立即返回,但并未读取到任何数据,用户线程需要不断发起 IO 请求,直到数据到达后,才真正读取到数据,继续执行;在整个 IO 请求的过程中,虽然用户线程每次发起 IO 请求后可以立即返回,但是为了等到数据,仍需要不断地轮询、重复请求、消耗大量 CPU 资源,一般很少使用这种模型,而是在其他 IO 模型中使用非阻塞 IO
IO 多路复用,是建立在内核上提供的多路分离函数 select 基础之上的,使用 select 函数可以避免同步非阻塞 IO 模型中轮询等待的问题;用户将需要进行 IO 操作的 socket 添加到 select 中,然后阻塞等待 select 系统调用返回。当数据到达时,socket 被激活,select 函数返回,用户线程发起 read 请求,读取数据并继续执行。使用 select 函数进行 IO 请求与同步阻塞模型并无太大区别,甚至多添加监视 socket,select 函数额外操作,使用优势主要在于用户可以在一个线程内同时处理多个 socket 的 IO 请求,用户可以注册多个 socket,然后不断调用 select 读取被激活的 socket,即可达到在同一个线程内同时处理多个 IO 请求的目的,同步阻塞模型中,必须使用多线程。
使用 select 允许单线程内处理多个 IO 请求,但是每个 IO 请求的过程还是阻塞的,平均时间甚至比同步阻塞 IO 模型还要长,IO 多路复用模型使用 Reactor 设计模式实现了这一机制,用户线程只注册自己感兴趣的 socket 或者 IO 请求,去做自己的事情,等到数据到来时再进行处理,可以提高 cpu 利用率;EventHandler 抽象类表示 IO 事件处理器,拥有 IO 句柄 get-handle,以及对 Handle 的操作 handle-event,继承于 EventHandler 的子类可以对事件处理器的行为进行定制,Reactor 类用于管理 EventHandler 注册、删除,并使用 handle-events 实现事件循环,不断调用内核中的多路分离函数 select,只要某个文件句柄被激活,select 就返回,就会调用 handle-event 事件处理器进行操作。
通过 reactor 的方式,将用户线程轮询 IO 操作状态的工作交给 handle-even 进行处理,用户线程进行事件注册之后进行其他工作(异步),而 reactor 线程负责调用内核 select 函数,当存在 socket 被激活时,通知相应的用户线程,执行 handle-event 进行数据读取、处理工作,由于 select 函数是阻塞的,所以多路 IO 复用也被称为异步阻塞 IO 模型,socket 是不被阻塞的,用户发起 IO 请求时,数据已经到达,用户线程一定不会被阻塞。其使用会阻塞线程的 select 系统调用,因此 IO 多路复用只能称为异步阻塞 IO,而非真正的异步 IO。
真正的异步 IO,需要操作系统更强的支持,在 IO 多路复用中,事件循环将文件句柄的状态事件通知给用户线程,由用户线程自行读取数据、处理数据,而在异步 IO 模型中,当用户线程收到通知时,数据已经被内核读取完毕,并放在用户线程指定的缓冲区内,内核在 IO 完成后通知用户线程直接使用即可。异步模型使用 Proactor 设计模式实现这一机制。
Proactor 和 Reactor 模式在结构上比较相似,在 Client 使用方式上差别较大,Proactor 模式中,用户线程将 AO、Proactor 以及操作完成时的 CompletionHandler 注册到 AOP。AOP 使用 Facade 模式提供一组异步操作 API 供用户使用,当用户线程调用异步 API 后,便执行自己的任务。AOP 会开启独立的内核线程执行异步操作,当异步 IO 完成时,AOP 将用户线程与 AOP 一起注册的 Proactor 和 CompletionHandler 取出,然后将 CompletionHandler 与 IO 操作的结果一致转发给 Proactor,Proactor 负责回调每一个异步操作事件完成处理函数 handle-event,Proactor 模式中每个异步操作都可以绑定一个 proactor 对象,一般操作系统中 Proactor 为单例模式,以便集中化分发操作完成事件。
异步 IO 模型中,用户线程直接使用内核提供的异步 IO API 发起 read 请求,发起后立即返回,继续执行用户线程代码。此时用户线程已经将调用的 AO 与 CH 注册到了内核,然后操作系统开启独立的内核线程去处理 IO 操作。当 read 请求的数据到达时,由内核负责读取 socket 中的数据,并写入用户指定的缓冲区中。最后内核将 read 的数据和用户线程注册的 CH 分发给内部 Proactor,Proactor 将 IO 完成的信息通知给用户线程,完成异步 IO。
异步 IO 并不常见,高性能并发服务程序,使用 IO 多路复用模型 + 多线程任务处理的架构基本可以满足要求,目前操作系统对异步 IO 的支持并非特别完善,更多的是采用 IO 多路复用模型模拟异步 IO 的方式,IO 事件触发时不直接通知用户线程,而是将数据读写完毕后放到用户指定的缓冲区中。 https://www.cnblogs.com/jianzihao/p/14814838.html
The text was updated successfully, but these errors were encountered:
No branches or pull requests
服务端编程需要构建高性能的 IO 模型,常见的 IO 模型主要有以下四种
同步与异步 用户线程与内核的交互方式;同步是指用户发起 IO 请求后,需要等待或者轮询内核 IO 操作完成后才能继续执行;异步是指用户线程发起 IO 请求后继续执行,当内核操作完成后会通知线程或者调用用户线程注册的回调函数
阻塞与非阻塞 用户线程调用内核 IO 操作的方式;阻塞是指 IO 操作需要彻底完成后才返回到用户空间,而非阻塞是指 IO 操作被调用后立即返回给用户一个状态值
同步阻塞 IO
用户线程通过系统调用 read 发起 IO 操作,由用户空间转到内核空间,内核等到数据包到达以后,将接受的数据拷贝到用户空间,完成 read,用户需要等待 read 将 socket 中的数据读取到 buffer 后,才继续处理接收的数据,整个 IO 请求过程中,用户线程是被阻塞的,导致用户发起请求时,不能做任何事情,对 CPU 资源利用不够。
同步非阻塞 IO
同步非阻塞 io,在同步阻塞 io 的基础上,将 socket 设置为 nonblock,用户线程可以在发起 io 请求后立即返回;socket 是非阻塞的方式,用户线程发起 IO 请求时立即返回,但并未读取到任何数据,用户线程需要不断发起 IO 请求,直到数据到达后,才真正读取到数据,继续执行;在整个 IO 请求的过程中,虽然用户线程每次发起 IO 请求后可以立即返回,但是为了等到数据,仍需要不断地轮询、重复请求、消耗大量 CPU 资源,一般很少使用这种模型,而是在其他 IO 模型中使用非阻塞 IO
IO 多路复用
IO 多路复用,是建立在内核上提供的多路分离函数 select 基础之上的,使用 select 函数可以避免同步非阻塞 IO 模型中轮询等待的问题;用户将需要进行 IO 操作的 socket 添加到 select 中,然后阻塞等待 select 系统调用返回。当数据到达时,socket 被激活,select 函数返回,用户线程发起 read 请求,读取数据并继续执行。使用 select 函数进行 IO 请求与同步阻塞模型并无太大区别,甚至多添加监视 socket,select 函数额外操作,使用优势主要在于用户可以在一个线程内同时处理多个 socket 的 IO 请求,用户可以注册多个 socket,然后不断调用 select 读取被激活的 socket,即可达到在同一个线程内同时处理多个 IO 请求的目的,同步阻塞模型中,必须使用多线程。
使用 select 允许单线程内处理多个 IO 请求,但是每个 IO 请求的过程还是阻塞的,平均时间甚至比同步阻塞 IO 模型还要长,IO 多路复用模型使用 Reactor 设计模式实现了这一机制,用户线程只注册自己感兴趣的 socket 或者 IO 请求,去做自己的事情,等到数据到来时再进行处理,可以提高 cpu 利用率;EventHandler 抽象类表示 IO 事件处理器,拥有 IO 句柄 get-handle,以及对 Handle 的操作 handle-event,继承于 EventHandler 的子类可以对事件处理器的行为进行定制,Reactor 类用于管理 EventHandler 注册、删除,并使用 handle-events 实现事件循环,不断调用内核中的多路分离函数 select,只要某个文件句柄被激活,select 就返回,就会调用 handle-event 事件处理器进行操作。
通过 reactor 的方式,将用户线程轮询 IO 操作状态的工作交给 handle-even 进行处理,用户线程进行事件注册之后进行其他工作(异步),而 reactor 线程负责调用内核 select 函数,当存在 socket 被激活时,通知相应的用户线程,执行 handle-event 进行数据读取、处理工作,由于 select 函数是阻塞的,所以多路 IO 复用也被称为异步阻塞 IO 模型,socket 是不被阻塞的,用户发起 IO 请求时,数据已经到达,用户线程一定不会被阻塞。其使用会阻塞线程的 select 系统调用,因此 IO 多路复用只能称为异步阻塞 IO,而非真正的异步 IO。
异步 IO
真正的异步 IO,需要操作系统更强的支持,在 IO 多路复用中,事件循环将文件句柄的状态事件通知给用户线程,由用户线程自行读取数据、处理数据,而在异步 IO 模型中,当用户线程收到通知时,数据已经被内核读取完毕,并放在用户线程指定的缓冲区内,内核在 IO 完成后通知用户线程直接使用即可。异步模型使用 Proactor 设计模式实现这一机制。
Proactor 和 Reactor 模式在结构上比较相似,在 Client 使用方式上差别较大,Proactor 模式中,用户线程将 AO、Proactor 以及操作完成时的 CompletionHandler 注册到 AOP。AOP 使用 Facade 模式提供一组异步操作 API 供用户使用,当用户线程调用异步 API 后,便执行自己的任务。AOP 会开启独立的内核线程执行异步操作,当异步 IO 完成时,AOP 将用户线程与 AOP 一起注册的 Proactor 和 CompletionHandler 取出,然后将 CompletionHandler 与 IO 操作的结果一致转发给 Proactor,Proactor 负责回调每一个异步操作事件完成处理函数 handle-event,Proactor 模式中每个异步操作都可以绑定一个 proactor 对象,一般操作系统中 Proactor 为单例模式,以便集中化分发操作完成事件。
异步 IO 模型中,用户线程直接使用内核提供的异步 IO API 发起 read 请求,发起后立即返回,继续执行用户线程代码。此时用户线程已经将调用的 AO 与 CH 注册到了内核,然后操作系统开启独立的内核线程去处理 IO 操作。当 read 请求的数据到达时,由内核负责读取 socket 中的数据,并写入用户指定的缓冲区中。最后内核将 read 的数据和用户线程注册的 CH 分发给内部 Proactor,Proactor 将 IO 完成的信息通知给用户线程,完成异步 IO。
异步 IO 并不常见,高性能并发服务程序,使用 IO 多路复用模型 + 多线程任务处理的架构基本可以满足要求,目前操作系统对异步 IO 的支持并非特别完善,更多的是采用 IO 多路复用模型模拟异步 IO 的方式,IO 事件触发时不直接通知用户线程,而是将数据读写完毕后放到用户指定的缓冲区中。
https://www.cnblogs.com/jianzihao/p/14814838.html
The text was updated successfully, but these errors were encountered: