前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >小白学协程笔记1-协程概念初识-2021-2-10

小白学协程笔记1-协程概念初识-2021-2-10

作者头像
用户7719114
发布2022-02-22 13:48:46
7920
发布2022-02-22 13:48:46
举报
文章被收录于专栏:C++小白C++小白

文章目录

前言

本文对协程的概念做了简要介绍,适合初次接触协程的小白。

一、从进程、线程到协程

1.进程

学习操作系统知识时,进程是必然绕不开的一个概念。什么是进程呢?简单来说,进程是程序的一个运行实例,是正在运行程序的一种抽象。比如当你打开游戏时,操作系统中就会创建一个游戏进程,当退出游戏时,对应进程也会终止。

那为什么要引入进程这一个概念呢?众所周知,操作系统具有并发、共享、异步、虚拟的特性。其中的并发性是指操作系统拥有“同时”处理多个事件的能力,比如我们在电脑上可以“同时”打游戏、听歌、看视频。在使用者角度,这些程序在宏观上同时运行。但是在操作系统角度,其实是游戏进程、听歌进程、视频进程在很短的时间片内交替在CPU上运行。所以,引入进程就可以方便操作系统实现并发等特性。

进程拥有程序和打开的文件资源、数据资源、独立的内存空间,不同的内存空间互不干扰。学习进程时肯定会了解到进程的三状态、五状态甚至七状态模型,最简单的三状态模型将进程分为运行态、阻塞态和就绪态。当进程在cpu上运行时就处于运行态,当进程由于等待某种资源而阻塞时就处于阻塞态,这时候进程会让出cpu给其他进程,当进程等待的资源到达时进程就处于就绪态,表示可以继续上cpu运行了。如下图所示:

在这里插入图片描述
在这里插入图片描述

2.线程

既然已经有了进程的概念,后面为何要引入线程呢?目的是提升操作系统性能,更好的实现并发。第一节提到,多个进程是交替在CPU上运行的,当进程在cpu上切换时,需要包存当前进程的上下文,切换到新调用进程的上下文,其中涉及到切换进程对应的页表、内核栈和用户栈等信息,开销是比较大的,所以要引入线程。

线程是操作系统进行调度的单位,引入线程以后程序的实际执行者变为了线程,每一个进程至少有一个线程。从操作系统角度看,同一个进程的多个线程共享进程的地址空间,但是每一个线程都有自己的栈。关于线程共享和私有资源的示意图如下:

在这里插入图片描述
在这里插入图片描述

引入线程后,当进程中的一个线程由于等待资源而阻塞时,就不用切换到其他进程,而是切换到进程中的另一个线程去执行其它任务。而线程切换时不用切换页表和内核栈,只用切换用户栈,所以开销要远远小于进程切换。这样就能有效提升效率和并发能力了。总结一下,对操作系统来说,线程是最小的执行单元,进程是最小的资源管理单元

3.协程

既然线程已经如此好用了,为何又要引入协程呢,无它,是因为科学家想要追求效率和并发的极致。协程也可以被称为微线程,是一种用户态内的上下文切换技术。简而言之,其实就是在一个线程内实现代码块相互切换执行的技术。协程在执行的过程中可以调用其他的协程,保护上下文切换到其他协程,之后协程调用返回恢复到调用的地址继续执行,这个过程类似于多线程的线程的切换。协程是比线程更加轻量级的存在,进程、线程切换都由操作系统内核控制,而协程切换只需要程序自己控制,不需要进入内核态,完全在用户态运行。所以协程切换的开销要比线程更小,可以支持更高的效率和并发。进程线程协程的示意图如下所示:

在这里插入图片描述
在这里插入图片描述

协程也有自己的缺点,当协程调用阻塞IO操作的时候,操作系统会让线程进入阻塞状态,这时协程和其它绑定在该线程之上的协程都会陷入阻塞而得不到调度。因此,协程一般和异步IO结合使用。

二、对称协程和非对称协程

协程一般分为对称协程和非对称协程两种,定义如下: 非对称协程(asymmetric coroutines)是跟一个特定的调用者绑定的,协程让出CPU时,只能让回给调用者。何为非对称呢?在于协程的调用(call/resume)和返回(return/yield)的地位不对等。程序控制流转移到被调用者协程,而被调用者只能返回最初调用它的协程。

对称协程(symmetric coroutines)在于协程调用和返回的地位是对等的。启动之后就跟启动之前的协程没有任何关系了。协程的切换操作,一般而言只有一个操作,yield,用于将程序控制流转移给其他的协程。对称协程机制一般需要一个调度器的支持,按一定调度算法去选择yield的目标协程。

三、常见语言对协程的支持

有哪些编程语言应用到了协程呢?如下所示: Lua语言:Lua从5.0版本开始使用协程,通过扩展库coroutine来实现。 Python语言:正python可以通过 yield/send 的方式实现协程。在python 3.5以后,async/await 成为了更好的替代方案。 Go语言:Go语言对协程的实现非常强大而简洁,可以轻松创建成百上千个协程并发执行。 Java语言:如上文所说,Java语言并没有对协程的原生支持,但是某些开源框架模拟出了协程的功能,有兴趣的小伙伴可以看一看Kilim框架的源码: C++:从c++20开始支持协程,但是c++20的协程标准只包含编译器需要实现的底层功能,并没有包含简单方便地使用协程的高级库,相关的类和函数进入std标准库估计要等到c++23。所以,在c++20中,如果要使用协程,要么等别人封装好了给你用,要么就要自己学着用底层的功能自己封装。

总结

本文对进程、线程、协程的概念做了简单介绍,相信大家对协程有了一个初步了解,但是协程在用户态是如何切换的呢?相信大家和我一样都有疑问,后面文章将结合代码进行学习介绍。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 文章目录
  • 前言
  • 一、从进程、线程到协程
    • 1.进程
      • 2.线程
        • 3.协程
        • 二、对称协程和非对称协程
        • 三、常见语言对协程的支持
        • 总结
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档