协程,英文名Coroutines,全称协同程序,协程无法由操作系统来实现,因为操作系统只能调度到线程,协程是比线程还小的单位。

因此协程只能依靠程序员来实现,程序员写完程序,然后再大脑里大致模拟出程序代码的运行顺序,在能够使用协程的地方加上协程,从而提升程序运行效率。

但是,不管三七二十一,我们都可以加上协程,即使效率提升并不高。

当出现IO阻塞时,CPU一直等待IO返回,处于空转状态。这时候用协程,可以执行其他任务。当IO返回结果后,再回来处理数据。充分利用了IO等待的时间,提高了效率。

又假设工作时,你写了一个程序,这个程序跑出结果需要5分钟,你明明可以在这5分钟内进行摸鱼,但是你的老板却让你这5分钟去帮他拿快递。这就是协程,在CPU没有进行计算而在等待数据交换时都得去工作计算其他程序的指令。

目录

一,协程的核心

二,协程与多线程的比较

三,协程的优点

四,协程的缺点

五,IO密集型和CPU密集型的概念

六,python实现协程

1,yield实现协程

2,asyncio实现协程(重点)


一,协程的核心

协程的核心是:控制流的让出与恢复

1,每个协程有自己的执行栈,可以保存自己的执行现场

2,可以由用户程序按需创建协程(比如:遇到io操作)

3,协程主动让出(yield)执行权的时候,会保存执行现场(保存中断时的寄存器上下文和栈),然后切换到其他协程。

4,协程恢复执行(resume)时,根据之前保存的执行现场恢复到中断前的状态,继续执行,这样就通过协程实现了轻量的由用户态调度的多任务模型。

二,协程与多线程的比较

请看下图:

1,在单线程同步模型中,任务按照顺序执行。如果某个任务因为I/O而阻塞,其他所有的任务都必须等待,直到它完成之后它们才能依次执行。

2,多线程版本中,这3个任务分别在独立的线程中执行。这些线程由操作系统来管理,在多处理器系统上可以并行处理,或者在单处理器系统上交错执行。这使得当某个线程阻塞在某个资源的同时其他线程得以继续执行。

3,协程版本的程序中,3个任务交错执行,但仍然在一个单独的线程控制中。当处理I/O或者其他昂贵的操作时,注册一个回调到事件循环中,然后当I/O操作完成时继续执行。回调描述了该如何处理某个事件。事件循环轮询所有的事件,当事件到来时将它们分配给等待处理事件的回调函数。

总结:协程问题的解决关键在于上下文切换,协程的上下文的关键数据似乎存在CPU的寄存器。

三,协程的优点

1,由于自身带有上下文和栈,无需线程上下文切换的开销,属于程序级别的切换,操作系统完全感知不到,因而更加轻量级;

2,原子操作的锁定及同步的开销;

3,方便切换控制流,简化编程模型

4,单线程内就可以实现并发的效果,最大限度地利用cpu,且可扩展性高,成本低(注:一个CPU支持上万的协程都不是问题。所以很适合用于高并发处理)

四,协程的缺点

1,无法利用多核资源:协程的本质是个单线程,它不能同时将 单个CPU 的多个核用上,协程需要和进程配合才能运行在多CPU上。

2,当然我们日常所编写的绝大部分应用都没有这个必要,除非是cpu密集型应用。

五,IO密集型和CPU密集型的概念

1,一个计算为主的应用程序(CPU密集型程序),多线程或多进程跑的时候,可以充分利用起所有的 CPU 核心数,比如说16核的CPU ,开16个线程的时候,可以同时跑16个线程的运算任务,此时是最大效率。但是如果线程数/进程数远远超出 CPU 核心数量,反而会使得任务效率下降,因为频繁的切换线程或进程也是要消耗时间的。因此对于 CPU 密集型的任务来说,线程数/进程数等于 CPU 数是最好的了。

2,如果是一个磁盘或网络为主的应用程序(IO密集型程序),一个线程处在 IO 等待的时候,另一个线程还可以在 CPU 里面跑,有时候 CPU 闲着没事干,所有的线程都在等着 IO,这时候他们就是同时的了,而单线程的话,此时还是在一个一个等待的。我们都知道IO的速度比起 CPU 来是很慢的。此时线程数可以是CPU核心数的数倍(视情况而定)。

总结:任务管理器里占用CPU很高的就是CPU密集型程序。打开一个软件,鼠标光标一直转圈卡死的就是IO密集型,微微卡死是因为没有CPU为程序进行处理。

六,python实现协程

asyncio协程是写爬虫比较好的方式。比多线程和多进程都好,开辟新的线程和进程是非常耗时的操作。

1,yield实现协程

我们知道,一个函数中只要写了yield,则他就是一个生成器。程序会在yield处挂起,直到next()方法将其唤醒。

import timedef func1():for i in range(3):print(f'北京:第{i}次打印啦')yield  # 只要方法包含了yield,就变成一个生成器time.sleep(1)def func2():g = func1()  # func1是一个生成器,func1()就不会直接调用,需要通过next()print(type(g))for k in range(3):print(f'上海:第{k}次打印了')next(g)  # 继续执行func1的代码time.sleep(1)if __name__ == '__main__':# 有了yield,我们实现了两个任务的切换+保存状态start_time = time.time()func2()end_time = time.time()print(f"耗时{end_time - start_time}")  # 耗时5.0秒,效率差别不大

基于yield并发执行,多任务之间来回切换,这就是个简单的协程的体现,但是他能够节省I/O时间吗?答案是:不能。

2,asyncio实现协程(重点)

1,正常的函数执行时是不会中断的,所以你要写一个能够中断的函数,就需要加 async,async的意思是异步。

2,async 是一个修饰符,用来声明一个函数为异步函数,异步函数的特点是能在函数执行过程中挂起,去执行其他,异步函数,等到挂起条件(假设挂起条件是 sleep(5) )消失后,也就是5秒到了再回来执行。

3,await()方法用来声明程序挂起,比如异步程序执行到某一步时需要等待的时间很长,就将此挂起,去执行其他的异步程序。

4,asyncio模块是python3.5之后的协程模块,是python实现并发重要的包,这个包使用事件循环驱动实现并发。

5,asyncio实现的是异步IO。也就是遇到IO阻塞时,不会干等待,而是跑去计算其他指定的指令。所谓IO阻塞,并不是说运行停止了,而是说IO过程费时间而已,IO过程CPU并不参与,而是一些其他硬件在忙活,比如硬盘和网卡向内存写数据。CPU需要等待这些数据放在内存之后才能操作。

下面介绍一个最简单的一部IO代码:

import asyncio
import timeasync def func1(sec):  # async表示方法是异步的,在函数变量名之前使用async修饰,说明该函数执行过程中可以被挂起,是一个协程对象而不是普通函数for i in range(sec):print(f'北京:第{i}次打印啦')await asyncio.sleep(1)  # await说明程序挂起,asyncio.sleep(1)是结束挂起的条件,也就是1s结束挂起,函数从挂起处继续执行,# 在这1s内,自动去执行其他协程,是协程而不是普通函数return "func1执行完毕"async def func2():for k in range(3):print(f'上海:第{k}次打印了')await asyncio.sleep(1)return "func2执行完毕"async def main():res = await asyncio.gather(func1(3), func2())  # asyncio.gather()方法,Return a future aggregating results from the given coroutines/futures.# await异步执行func1方法# 返回值为函数的返回值列表print(res)if __name__ == '__main__':start_time = time.time()asyncio.run(main())end_time = time.time()print(f"耗时{end_time - start_time}")  # 耗时3秒,效率极大提高

python协程入门介绍相关推荐

  1. Python协程原理介绍及基本使用

    目录 1.什么是协程? 2.协程运行主要原理 3.小结 1.什么是协程? 协程是实现并发编程的一种方式.一说到并发,你肯定想到了多线程 / 多进程模型,没错,多线程 / 多进程,正是解决并发问题的经典 ...

  2. python 协程可以嵌套协程吗_Python线程、协程探究(2)——揭开协程的神秘面纱...

    一.上集回顾 在上一篇中我们主要研究了python的多线程困境,发现多核情况下由于GIL的存在,python的多线程程序无法发挥多线程该有的并行威力.在文章的结尾,我们提出如下需求: 既然python ...

  3. c++ 协程_理解Python协程(Coroutine)

    由于GIL的存在,导致Python多线程性能甚至比单线程更糟. GIL: 全局解释器锁(英语:Global Interpreter Lock,缩写GIL),是计算机程序设计语言解释器用于同步线程的一种 ...

  4. 简单聊聊Python协程

    往期好文推荐 学习Python不需要程基础? 0基础不用怕,从0到1轻松教你入门Python python系统学习流线图,教你一步一步学会python 成为一名做大数据开发的女程序员,并不是二狗进入大 ...

  5. Kotlin协程入门初级篇

    协程包含很多的功能点,这边只是一些基本功能点的介绍,只适合小白,已经掌握的可以忽略~ 协程入门(一):协程介绍与调用方式 协程入门(二):挂起与取消 协程入门(三):调度器 协程入门(四):启动模式 ...

  6. python协程详解

    目录 python协程详解 一.什么是协程 二.了解协程的过程 1.yield工作原理 2.预激协程的装饰器 3.终止协程和异常处理 4.让协程返回值 5.yield from的使用 6.yield ...

  7. python协程系列(三)——yield from原理详解

    声明:本文将详细讲解python协程的实现机理,为了彻底的弄明白它到底是怎么一回事,鉴于篇幅较长,将彻底从最简单的yield说起从最简单的生成器开始说起,因为很多看到这样一句话的时候很懵,即" ...

  8. python yield 协程_用yield实现python协程

    刚刚介绍了pythonyield关键字,趁热打铁,现在来了解一下yield实现协程. 引用官方的说法: 与线程相比,协程更轻量.一个python线程大概占用8M内存,而一个协程只占用1KB不到内存.协 ...

  9. 5分钟完全掌握Python协程

    1. 协程相关的概念 1.1 进程和线程 进程(Process)是应用程序启动的实例,拥有代码.数据和文件和独立的内存空间,是操作系统最小资源管理单元.每个进程下面有一个或者多个线程(Thread), ...

最新文章

  1. 隐式转换和显式转换及强制转换的区别
  2. C语言合理字符的代码,改善C语言程序代码的125个建议,第62到89个建议!
  3. java ing印版,Java中有趣的事【汇总】持续更新ing
  4. 有气质的人都在看什么?
  5. Python_socketserver
  6. 软件测试的含义以及测试的对象
  7. 一个 TypeScript keyof 泛型用法
  8. VS Code 下载安装并设置中文面板显示
  9. 20190925每日一句
  10. erroe C1083:无法打开包括文件(源文件)
  11. 8. 查询表orders——统计各类商品的销售量
  12. 广告代码(弹窗和富媒体)
  13. 笔记本电脑外接显示器投屏问题
  14. 字节跳动面试:京东面试真题解析,薪资翻倍
  15. excel求方差和标准差的函数_Excel计算方差和标准差
  16. FL Studio教程之Riff机的简介
  17. 在IntelliJ IDEA中,开发一个摸鱼看书插件
  18. WARNING [main] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web appli
  19. S32K系列S32K144学习笔记——ADC
  20. 如何获取数组中的最后几项:slice()

热门文章

  1. 笔记本电脑的电池健康:确保长时间使用和优异性能的关键
  2. Java中Runtime类详细总结
  3. Iphone开发中的web开发
  4. pdf文件在pdfbox中对应的数据结构的一点浅见
  5. SpringDataJpa的使用 -- 一对一、一对多、多对多 关系映射
  6. PlayMaker — 事件
  7. 看完Spring源码记不住,是我脑子不太好吗?
  8. 罗技鼠标不能正常设置滚动属性的问题
  9. 天载优配大盘尝试站稳反弹
  10. windows JDK11.0.15下载及环境配置