讲得非常透彻
1. cpu的工作是解释计算机中的指令,和处理计算机软件中的数据
2.进程,一个进程就是一个具有独立功能的应用程序,关于某个数据集合上的一次运行活动。进程是系统进行资源分配和调度的一个独立单位。
3. 线程,线程是进程的实体,属于进程,是CPU调度和分派的基本单位。
资源分配给进程,所有线程共享该进程的资源
BIO一个连接一个线程,不管有没有实际的事情在处理,socket在accept、read、write的时候都在等待,占用着线程:https://www.cnblogs.com/promise-7/p/12574499.html
https://www.zhihu.com/search?type=content&q=%E4%B8%BE%E4%BE%8B%E8%AF%B4%E6%98%8Ecpu%E5%92%8C%E7%BA%BF%E7%A8%8B%E7%9A%84%E5%85%B3%E7%B3%BB
多线程和CPU的关系:https://www.cnblogs.com/fubaizhaizhuren/p/7501403.html
马士兵讲解aio,nio,bio
https://blog.csdn.net/qq_41063141/article/details/116459793
https://www.cnblogs.com/zlj123/p/6635460.html
https://segmentfault.com/a/1190000015083939
ajax异步原理
javascript是如何实现异步的
https://www.jianshu.com/p/1a35857c78e5
https://www.cnblogs.com/goloving/p/9393541.html
js如何实现的异步
问题记录
- 数据从网卡到内存,这一步是操作系统来做的,处理请求的线程到这一步时如果要不断轮询等待就是同步,处理请求的线程到这一步时不需要等待,而是可以继续干别的事情,然后等待操作系统的完成通知的话就是异步。【10个请求过来,10个线程会去处理,同步模式:每个线程都会经历等待操作系统将数据从网卡读到内存,这是资源浪费。异步模式:当操作系统完成了就去通知这10个线程】
同步,异步,阻塞,非阻塞简述
了解bio,nio,aio的前置条件要了解下面的概念:
同步:java自己处理io读写
异步:java把io操作委托给os处理,且要把数据缓冲区大小和地址传给os,os要支持异步io操作的api.
阻塞:java调用会一直阻塞直到读写完成。
非阻塞:如果不能进行读写,java调用会立即返回,当io事件分发器通知可读写时再继续进行io读写,一直循环直到读写完成。
初识bio,nio,aio
bio :同步阻塞,服务器实现模式是一个连接一个线程,当客户端发来连接时服务器就需要启动一个线程进行处理,如果这个连接不做任何事情就会造成不必要的线程开销,当然线程池机制可以改善。
nio:同步非阻塞,服务器实现模式为多个请求一个线程,即客户端发来的请求都会注册到多路复用器上,多路复用器轮训的连接有io请求时才开启一个线程进行处理。
aio:异步非阻塞,服务器实现模式为多个有效请求一个线程。即客户端发来的请求由os处理完成才会通知服务器应用启动线程进行处理。
我感觉异步和同步的概念贯穿在应用层(操作系统向用户提供同步异步接口),操作系统内核层次(与DMA设备交互),物理层(硬件通信也有异步io和同步io之分),必须分开讨论才有意义。
比如,epoll之所以能实现,就是因为底层硬件实现了DMA机制,才能够注册回调函数,从cpu与硬件交互的角度上看,这是异步的,但epoll本身要阻塞在那里等待socket,所有epoll又属于同步io
而阻塞非阻塞更多是针对操作系统上的进程和线程来说的,对于一个进程,如果要等待io才返回,它就是阻塞的,它也可以开启多线程去处理一个本是阻塞的socket.accept,这样对这个进程来说就是非阻塞了。但accept具体处理的时候往下一级硬件既可能是非DMA设备(同步),也可以是DMA设备(异步),从这个角度上看,阻塞和非阻塞与异步同步没有关系
不知道这样理解是否正确
作者:卢毅luis
链接:https://www.zhihu.com/question/19732473/answer/20851256
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
“阻塞”与"非阻塞"与"同步"与“异步"不能简单的从字面理解,提供一个从分布式系统角度的回答。1.同步与异步同步和异步关注的是消息通信机制 (synchronous communication/ asynchronous communication)所谓同步,就是在发出一个调用时,在没有得到结果之前,该调用就不返回。但是一旦调用返回,就得到返回值了。换句话说,就是由调用者主动等待这个调用的结果。而异步则是相反,调用在发出之后,这个调用就直接返回了,所以没有返回结果。换句话说,当一个异步过程调用发出后,调用者不会立刻得到结果。而是在调用发出后,被调用者通过状态、通知来通知调用者,或通过回调函数处理这个调用。典型的异步编程模型比如Node.js举个通俗的例子:
-
你打电话问书店老板有没有《分布式系统》这本书,如果是同步通信机制,书店老板会说,你稍等,”我查一下",然后开始查啊查,等查好了(可能是5秒,也可能是一天)告诉你结果(返回结果)。而异步通信机制,书店老板直接告诉你我查一下啊,查好了打电话给你,然后直接挂电话了(不返回结果)。然后查好了,他会主动打电话给你。在这里老板通过“回电”这种方式来回调。
-
阻塞与非阻塞阻塞和非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态.阻塞调用是指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程。
-
还是上面的例子,你打电话问书店老板有没有《分布式系统》这本书,你如果是阻塞式调用,你会一直把自己“挂起”,直到得到这本书有没有的结果,如果是非阻塞式调用,你不管老板有没有告诉你,你自己先一边去玩了, 当然你也要偶尔过几分钟check一下老板有没有返回结果。在这里阻塞与非阻塞与是否同步异步无关。跟老板通过什么方式回答你结果无关。
其他楼层包括从技术角度都有了详细解释。这里主要是针对其他网友的疑问做的补充和修改,考虑到需要在编程概念上更严谨一点。阻塞非阻塞表示下面 买书过程中 可能出现的状态,是从 我 这个单进程角度来看待这个买书这个问题。同步异步表示一种协作方式,是从全局更高的角度 “进程之间 合作的方式” 来看待买书这个业务。两个进程之间如果商量采用异步方式处理买书这一业务,就不存在阻塞这种状态。
作者:Shihui wang
链接:https://www.zhihu.com/question/19732473/answer/14413599
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
一次网络请求所涉及的过程分析(用户态内核态的切换,同步异步阻塞非阻塞,tcp执行过程)
内核态(内核空间)和用户态(用户空间)的区别和联系
系统将虚拟空间(内存)分为了内核空间、用户空间,处于用户态的程序只能访问用户空间,而处于内核态的程序可以访问用户空间和内核空间。我们的应用程序(tomcat,navicat…)是处于用户态,当遇到系统调用(文件io,fork()创建新进程),异常(缺页异常,整数除0的程序异常),外围设备的中断(u盘读写操作,完成操作后设备会向cpu发起中断,系统会从先前执行的指令是用户态下的程序切换到内核态执行后续操作)会从内核态切换到用户态(比较耗时,开销较大)
操作系统~用户态进入内核态的方式(中断、异常、系统调用)–讲得很好
对于磁盘读操作,网络请求操作
对于一个read操作经历两个阶段:一是将数据(磁盘文件)copy到内核空间【等待数据/数据准备阶段】,二是将数据从内核空间copy到用户空间【内核空间复制数据到用户进程缓冲区(用户空间)阶段】,这样read才算完成
对于socket流而言经历两个阶段:一是将等待网络数据到达网络缓冲区【等待数据】,将数据copy到内核空降,二是将数据从内核空间copy到用户空间
udp的执行过程
(1)使用函数socket(),生成套接字文件描述符;
(2)通过struct sockaddr_in 结构设置服务器地址和监听端口;
(3)使用bind() 函数绑定监听端口,将套接字文件描述符和地址类型变量(struct sockaddr_in )进行绑定;
(4)接收客户端的数据,使用recvfrom() 函数接收客户端的网络数据;
(5)向客户端发送数据,使用sendto() 函数向服务器主机发送数据;
(6)关闭套接字,使用close() 函数释放资源;
再看三种模型
10个请求过来,服务端会new10个线程,在数据准备阶段,每个线程都会进行系统调用去询问数据准备好了吗。(这会进行10次用户态到内核态的切换)
IO复用的三种模型select,poll,epoll–附有代码实现
- io多路复用
术语描述:进程通过将一个或多个fd传递给select,阻塞在select操作上,select帮我们侦测多个fd是否准备就绪,当有fd准备就绪时,select返回数据可读状态,应用程序再调用recvfrom读取数据。【一个请求会有唯一的一个fd文件描述符进行标识】
一个单线程的select(大管家)监听了多个socket
两个应用程序之间的tcp通信为例(A向B发送消息)
思考一个问题:
因为应用之间发送消息是间断性的,也就是说在上图中TCP接收缓冲区还没有接收到属于应用B该读取的消息时,那么此时应用B向TCP缓冲区发起读取申请,(TCP接收缓冲区还没有收到数据)TCP接收缓冲区是应该马上告诉应用B 现在没有你的数据,还是说让应用B在这里等着,直到有数据再把数据交给应用B。
把这个问题应用到第一个步骤也是一样,应用A在向TCP发送缓冲区发送数据时,如果TCP发送缓冲区已经满了,那么是告诉应用A现在没空间了,还是让应用A等待着,等TCP发送缓冲区有空间了再把应用A的数据访拷贝到发送缓冲区。
【传统io模型是来一个请求就new一个线程去处理,每个线程都会自己调用recvfrom 去读取数据】
我们还是把视角放到应用B从TCP缓冲区中读取数据这个环节来。如果在并发的环境下,可能会N个人向应用B发送消息,这种情况下我们的应用就必须创建多个线程去读取数据,每个线程都会自己调用recvfrom 去读取数据。那么此时情况可能如下图:
如上图一样,并发情况下服务器很可能一瞬间会收到几十上百万的请求,这种情况下应用B就需要创建几十上百万的线程去读取数据,同时又因为应用线程是不知道什么时候会有数据读取,为了保证消息能及时读取到,那么这些线程自己必须不断的向内核发送recvfrom 请求来读取数据;
那么问题来了,这么多的线程不断调用recvfrom 请求数据,先不说服务器能不能扛得住这么多线程,就算扛得住那么很明显这种方式是不是太浪费资源了,线程是我们操作系统的宝贵资源,大量的线程用来去读取数据了,那么就意味着能做其它事情的线程就会少。
所以,有人就提出了一个思路,能不能提供一种方式,可以由一个线程监控多个网络请求(我们后面将称为fd文件描述符,linux系统把所有网络请求以一个fd来标识),这样就可以只需要一个或几个线程就可以完成数据状态询问的操作,当有数据准备就绪之后再分配对应的线程去读取数据,这么做就可以节省出大量的线程资源出来,这个就是IO复用模型的思路。
- 异步io
思考一个问题:
也许你一开始就有一个疑问,为什么我们明明是想读取数据,什么非得要先发起一个select询问数据状态的请求,然后再发起真正的读取数据请求,能不能有一种一劳永逸的方式,我只要发送一个请求我告诉内核我要读取数据,然后我就什么都不管了,然后内核去帮我去完成剩下的所有事情?
当然既然你想得出来,那么就会有人做得到,有人设计了一种方案,应用只需要向内核发送一个read 请求,告诉内核它要读取数据后即刻返回;内核收到请求后会建立一个信号联系,当数据准备就绪,内核会主动把数据从内核复制到用户空间,等所有操作都完成之后,内核会发起一个通知告诉应用,我们称这种一劳永逸的模式为异步IO模型。
同步异步阻塞非阻塞
对于一个线程的io有如下分类:同步io,异步io,阻塞io,非阻塞io
对于两个线程之间的调用有如下分类:同步调用,异步调用
同步与异步是对应于调用者与被调用者,它们是线程之间的关系,两个线程之间要么是同步的,要么是异步的
阻塞与非阻塞是对同一个线程来说的,在某个时刻,线程要么处于阻塞,要么处于非阻塞【比如文件下载:线程先执行查询操作(假设非阻塞),然后进行磁盘io(比较耗时,假设阻塞了,则线程会先挂起,即停/卡在了这步操作上)】
-
同步阻塞方式:
发送方发送请求之后一直等待响应。
接收方处理请求时进行的IO操作如果不能马上等到返回结果,就一直等到返回结果后,才响应发送方,期间不能进行其他工作。 -
异步非阻塞方式:
发送方向接收方请求后,不等待响应,可以继续其他工作。
接收方处理请求时进行IO操作如果不能马上得到结果,也不等待,而是马上返回去做其他事情。
当IO操作完成以后,将完成状态和结果通知接收方,接收方再响应发送方。(效率最高)
参考文章
内核态(内核空间)和用户态(用户空间)的区别和联系
彻底理解同步 异步 阻塞 非阻塞