Go学习笔记-协程和IO多路复用

简介: Go学习笔记-协程和IO多路复用

1、什么是协程?

  • 进程的虚拟地址空间划分为用户空间和内核空间
  • 线程是进程中的执行体,拥有一个执行入口,以及从虚拟地址空间中分配的栈(包括用户栈和内核栈)
  • 操作系统会记录线程控制信息,线程在获得时间片就可以被执行,CPU的指令指针和栈指针就会记录和执行线程相关的信息
  • 当线程创建了很多个执行体,并且也给这些执行体指定入口和分配栈内存,就可以按需调度这些执行体
  • 线程为了控制这些执行体的切换,也会记录这些执行体的信息,如ID、栈的位置、执行入口、执行现场等数据
  • 上述这种由线程创建的执行体就被称为协程,操作系统对协程一无所知,所以协程也可被称为用户态线程


2、协程间切换

  • 当用户线程获得CPU的时间片后,可以创建很多协程
  • 某个协程让出执行权时,会有协程栈保存执行现场等信息,接着就可以切换到其他协程
  • 协程获得执行权时,会根据之前协程栈保存的现场信息数据恢复执行
  • 协程是由用户态调度的多任务模型

3、协程和IO多路复用

  • 高并发成为为主流趋势,多进程模型请求下内存资源紧张
  • 多进程模型下,内核态和用户态切换两头忙
  • 协程这种用户态调度模型受到了关注
  • 协程和IO多路复用的结合成为很好的高并发解决方案

4、IO多路复用

  • 通过操作系统的进程控制信息可以找到进程打开文件描述信息、创建socket信息等
  • socket的操作都由操作系统来完成,需要用户程序通过系统调用来完成
  • 每创建一个socket,就会在打开的文件描述符表中创建一条记录信息,返回给用户程序的是socket描述符
  • 每个TCP socket被创建时,操作系统都会在内核空间分配度缓冲区、写缓冲区
  • 获取响应数据时,需要从读缓冲区拷贝数据
  • 要通过socket发送数据时,先要把数据拷贝到写缓冲区

  • 问题来了:
  • 当用户程序想要从读缓冲区获取数据,不一定有
  • 当用户程序想要发送数据的时候,写缓冲区,不一定有空间
  • 解决办法:
  • 阻塞式IO
  • 让出CPU进到等待队列里,等socket准备就绪,再次获得时间片时就可以继续执行了
  • 要处理一个socket,就需要占用一个线程,处理完才能继续下一个
  • 高并发场景下,开销很大
  • 非阻塞式IO
  • 不让出CPU,但需要一直询问socket是否准备就绪
  • 但这种忙等待的方式可能会空耗CPU,增加响应延迟
  • IO多路复用
  • 操作系统把需要等待的socket加入到监听集合
  • 用户程序就可以通过一次系统调用同时监听多个socket
  • Linux提供三种IO多路复用方式:
  • select
  • 可以设置要等待的描述符,也可以设置要等待的超时时间
  • 如果有准备好的fd,或到了超时时间,select系统函数就会返回
  • select系统函数支持可读、可写、可执行
  • fd_set是一个unsigned long数组,16个元素,每一位对应一个fd,最多可以监听1024个
  • 并且每次调用都需要传递所有监听的集合,需要频繁的从用户态到内核态拷贝数据
  • 每次都需要遍历整个监听集合判断可操作的fd

  • poll
  • 只能解决最大监听fd描述符的个数,其他问题依然没有得到解决

  • epoll
  • epoll提供三个关键接口
  • epoll_create用于创建epoll句柄
  • epoll_ctl用于添加或删除fd与对应的事件信息,可以指定要监听的fd和事件类型,可以传入额外的data数据,每次只需要传入一个fd,无需传入所有fd集合
  • epoll_wait返回fd集合都是已经准备就绪的,这样就不会阻塞和空耗CPU了
  • epoll有什么问题:
  • 比如当某个线程读fd时,可能读到一半时,CPU时间片就到了,需要让出执行权,保存现场数据
  • 需要等到下一次时间片的CPU执行权时,才能恢复现场继续执行
  • 解决办法:
  • 频繁切换线程,需要保存和恢复执行现场
  • 可以交给协程来处理,对于CPU来说同一个线程的多个协程无感知
  • 协程拥有自己的栈空间,用于保存和恢复现场相对比较容易,和具体的线程业务逻辑解耦了
相关文章
|
19天前
|
开发者 Python
深入浅出Python协程:提升IO密集型应用性能
在当今快速发展的软件行业中,提升应用性能已成为开发者追求的重要目标之一。特别是对于IO密集型应用,如何有效利用有限的系统资源以提高并发处理能力,成为了一个值得深入探讨的话题。本文将通过深入浅出的方式,介绍Python协程的基本概念、工作原理及其在提升IO密集型应用性能中的应用。通过具体示例,我们将展示如何使用Python的asyncio库来实现协程,以及如何通过协程优化网络请求和文件操作等IO操作,从而显著提高应用的响应速度和吞吐量。
9 1
|
20天前
|
监控 安全 Java
Go语言学习笔记(一)
Go语言学习笔记(一)
88 1
|
1月前
|
网络协议 架构师 Linux
一文说透IO多路复用select/poll/epoll
一文说透IO多路复用select/poll/epoll
108 0
|
1月前
|
网络协议 Linux
2.1.1网络io与io多路复用select/poll/epoll
2.1.1网络io与io多路复用select/poll/epoll
|
1月前
|
存储 网络协议
TCP服务器 IO多路复用的实现:select、poll、epoll
TCP服务器 IO多路复用的实现:select、poll、epoll
28 0
|
1月前
|
网络协议 Linux C++
Linux C/C++ 开发(学习笔记十二 ):TCP服务器(并发网络编程io多路复用epoll)
Linux C/C++ 开发(学习笔记十二 ):TCP服务器(并发网络编程io多路复用epoll)
32 0
|
1月前
|
监控 Linux
IO多路复用,epoll和select的区别
IO多路复用,epoll和select的区别
15 0
|
1月前
|
网络协议 编译器 Linux
协程和IO多路复用
协程和IO多路复用
33 0
协程和IO多路复用
|
1月前
|
存储 监控 网络协议
|
1月前
|
监控 NoSQL Linux
网络IO管理 - 多路复用IO
网络IO管理 - 多路复用IO