swoole学习第七讲(学习swoole需要掌握的知识)

轮询、长轮询、长连接、单工、全双工、半双工区别
  • 轮询:客户端发送request请求,服务端回应response响应,连接关闭,循环往复
  • 长轮询:客户端发送request请求并设置较长的超时时间,服务端在一段时间内查询(比如循环10此,每次循环sleep 1s),该请求10秒后返回,如果在这段时间内查询到,服务器将立即返回,客户端重新发起新的请求
  • 长连接:双方建立起连接不断开,如果有新的数据需要传输,则直接复用这个连接,无需再建立一个新的连接
  • 短连接: 双方建立连接后,数据传输完就断开,如果需要继续发送数据,则还需要继续建立新的连接
  • 单工:一方只能发信息,另一方则只能收信息,通信是单向的。
  • 半双工:双方都能发信息,但同一时间则只能一方发信息。
  • 全双工:双工在同一时间可以互相发送消息
socket、websocket、http之间的关系
TCP/IP分层模型
  • socket: 是位于应用层传输控制层(tcp/ip层)之间的一层抽象出来的接口(interface)接口如果想要被人使用那么需要具体的实现类(class)去实现, socket适用于多种网络协议,主流的就是tcp/ip,我们按照socket接口规范实现对tcp/ip协议的封装,我们把这种规范叫做socket
  • websocket and http
差异 websocket http
数据传输方式 双工 单工
消息模式 bi-direction(双向) request/response
服务器推技术x 默认支持 request/response
开销 建立连接开销适中
后续发送消息最小化开销
每个请求开销适中
连接方式 长连接(协议本身实现) http1.0短连接/http1.1长连接
利用的是tcp/ip层面实现的长连接)
媒介/优势 缓存 不可能支持 核心特性
基于协议 TCP/IP TCP/IP
通信模型 socket socket
协议层次 应用层协议 应用层协议
可靠性 可靠 可靠
依赖关系 依赖http协议
靠http头转换为websocket协议
不依赖
适用场景 实时性高 不需要实施更新/高度可缓存
支持范围 现代语言、客户端 广泛支持
http/websocket 它们之间的关系

更多场景参考:https://cs.xieyonghui.com/architecture/65.html

并行、并发、同步、异步、阻塞、非阻塞、进程、线程、CPU核心之间的关系
  • CPU核心:是指物理上,也就是硬件上存在着几个核心。比如,双核就是包括2个相对独立的CPU核心单元组,四核就包含4个相对独立的CPU核心单元组。
  • 进程:是并发执行的程序在执行过程中分配和管理资源的基本单位,是一个动态概念,竞争计算机系统资源的基本单位。
  • 线程:是进程的一个执行单元,是进程内科调度实体。比进程更小的独立运行的基本单位。线程也被称为轻量级进程。
    进程、线程关系
  • 并行同一时刻(比如3:00这一个时刻)执行多个任务,比如我们的电脑是4核心的,最少同时可以支持4个线程同时运行(intel超线程技术一个核心可以模拟多个线程)
  • 并发一段时间内(比如3:00~~4:00)执行多个任务,同一时刻只有一个任务在执行,只是因为CPU执行太快了,我们没有感觉到
  • 同步IO同步IO整个过程进程(Process)会被阻塞,直到内核(Kernel)同步IO操作被完成,内核(Kernel)返回执行结果,进程(Process)解除阻塞
  • 异步IO异步IO整个过程进程(Process)不会被阻塞,当内核执行IO任务完成时,内核(Kernel)会主动发送完成回调(信号)给进程(Process),告诉进程(Process)执行完了,期间IO任务靠内核(Kernel)来完成,和进程(Process)没有关系
  • 阻塞IO阻塞IO整个过程进程(Process)会被阻塞,直到内核(Kernel)阻塞IO操作被完成,内核(Kernel)返回执行结果,进程(Process)解除阻塞
  • 非阻塞IO非阻塞IO只有当内核(Kernel)执行真正的IO操作时才会被阻塞,在执行非IO操作时并不会阻塞IO,执行IO操作是靠进程(Process)不断的去询问,最终内核(kernel)去执行,等待IO完成后一并返回给进程(Process)执行结果,解除进程(Process)阻塞

阻塞/非阻塞侧重说明IO过程中进程的状态,同步/异步侧重说IO完成后进程获取结果的一个方式

办港台通行证可以去出入境大厅办,也可以在网上办,办完后直接寄给你。

  • 异步IO(网上办):网上填好资料,其他的你就不用管了,该干嘛干嘛。直到收到通行证。OK,你现在可以去香港澳门嗨了。
  • 大厅办,又可以分两种情况:
  • 阻塞IO(排队等候):在排队的过程中你不能跑去做其他事情了吧。直到排到你了,你就和办证的美女姐姐完成办证过程,这个过程你也是离开不了。
  • 非阻塞IO(叫号等候):人民政府觉得办证要人性化,所以采用了叫号机制。你拿了号以后,可以在大厅中呆着时不时看看大屏幕是不是排到你了,或者出去抽根烟逛个街看个美女,再回来看看是不是排到你了。直到排到你了,你就需要到窗口完成办证过程了。
  • IO多路复用(雇人排队): 假设有一个人只要给他钱,他就可以拿着你的号替你排队,但是办证过程需要你本人。所以排到你的号了,他就打个电话叫你回来办。这样你就可以同时帮你爸妈三姑六婆等等办通行证一起办了。这就是IO多路复用了,你街也逛得爽了,美女也看够了,还能同时办多个通行证,这过程简直爽呆。但就是需要另外付给号阪机构钱,开销比自己排队多了。
  • 所以上面几种方式中,异步IO最省事,IO多路复用也挺好用的,只不过多了一次系统调用的(select/poll/epoll)开销。
  • 详细参考https://blog.csdn.net/historyasamirror/article/details/5778378

另一个关于同步和异步 阻塞非阻塞的例子感觉不错

老张爱喝茶,废话不说,煮开水。出场人物:老张,水壶两把(普通水壶,简称水壶;会响的水壶,简称响水壶)。
1 老张把水壶放到火上,立等水开。(同步阻塞)
老张觉得自己有点傻

2 老张把水壶放到火上,去客厅看电视,时不时去厨房看看水开没有。(同步非阻塞)
老张还是觉得自己有点傻,于是变高端了,买了把会响笛的那种水壶。水开之后,能大声发出嘀~~~~的噪音。

3 老张把响水壶放到火上,立等水开。(异步阻塞)
老张觉得这样傻等意义不大

4 老张把响水壶放到火上,去客厅看电视,水壶响之前不再去看它了,响了再去拿壶。(异步非阻塞)
老张觉得自己聪明了。所谓同步异步,只是对于水壶而言。

普通水壶,同步;响水壶,异步。
虽然都能干活,但响水壶可以在自己完工之后,提示老张水开了。
这是普通水壶所不能及的。同步只能让调用者去轮询自己(情况2中),造成老张效率的低下。
所谓阻塞非阻塞,仅仅对于老张而言。
立等的老张,阻塞;看电视的老张,非阻塞。
情况1和情况3中老张就是阻塞的,媳妇喊他都不知道。
虽然3中响水壶是异步的,可对于立等的老张没有太大的意义。
所以一般异步是配合非阻塞使用的,这样才能发挥异步的效用。

为什么有HttpServer、WebSocketServer、TcpServer、UdpServer,它们之间的关系是什么,该选择什么?

HttpServer:应用层协议,对传输层协议在封装,遵循http协议
WebSocketServer: 应用层协议,对传输层协议在封装,基于http协议,遵循websocket协议
TcpServer 传输层协议
UdpServer: 传输层协议
如下图,顶层为应用层,中间通过socket抽象层关联到传输层

总结:Http/websocket协议是基于传输层tcp/udp协议实现的传输层协议,更加方便开发人员使用,应用层协议能实现的,通过传输层协议也能实现,在以快速实现功能的前提下,当让挑最简单的来使用了,如果你不想加班的话。同理,这些server是相应协议的实现,websocket支持长连接,http不支持长连接,根据对应的业务选择相应的server

  • 举个例子
    TCP实现了Socket接口,而TCP是面向stream传输的,直接用Socket容易出问题,比如粘包问题。WebSocket是一个应用层协议,更抽象,不需要考虑这些问题。所以当然可以直接用Socket实现长连接,不过仍然需要实现自己的上层协议来处理分包,比较麻烦,不如直接用WebSocket。自己的客户端使用自己的私有协议还行,但浏览器的话更需要一个统一的应用层协议,所以WebSocket就出现了。
IO/CPU之间的关系
  • 计算机硬件上CPU通过DMA来访问磁盘等IO,也就是请求发出后,CPU就不再管了,直到DMA处理器完成任务,再通过中断告诉CPU完成了。所以,单独的一个IO时间,对CPU的占用是很少的,阻塞了就更不会占用CPU了,因为程序都不继续运行了,CPU时间交给其它线程和进程了。虽然IO不会占用大量的CPU时间,但是非常频繁的IO还是会非常浪费CPU时间的,所以面对大量IO的任务,有时候是需要算法来合并IO,或者通过cache来缓解IO压力的。

总结:在涉及到IO操作时,CPU是只管发IO指令的,具体的读取、并将读到的信息处理是硬盘自己自己来实现的,DMA是跑腿的

协程
  • 协程:协程是一种用户态的轻量级线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。总结下来相当于实现了一个内核调度器,这个内核调度器在操作系统层面上是抢占式的,但是协程所实现的调度器是协同式。

众所周知swoole和go都实现了协程,但是两者之间还是有些不同的,详见swoole官网介绍 https://wiki.swoole.com/wiki/version/?id=1018&version=5

在编程中,会遇到IO密集型和CPU密集型这两种情况
swoole为什么线程安全:swoole一个进程下同时只有一个线程在执行任务,当任务类型为CPU密集型时,因为只有一个线程,所以在操作堆(heap)数据时不需要使用锁,go语言时多线程,操作堆(heap)数据时多个线程需要加锁,由于swoole设计的原因,所以时线程安全的,但是执行IO密集操作这又是另一回事了,需要为了保证数据的一致性,还是要加锁,比如数据库的行锁等。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容