Python 协程
Posted hybb
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python 协程相关的知识,希望对你有一定的参考价值。
协程
- 进程:操作系统中存在
- 线程:操作系统中存在
- 协程:是微线程 模块(greenlet)
协程不是一个真实存在的东西,是由程序员创造出来的
协程,是对一个线程分片,使得线程在代码块之间进行来回切换,而不是原来逐步执行。
单纯的协程是无用的,有时候而且会降低性能
示例代码:
import greenlet
def f1():
print(11)
gr2.switch()
print(22)
gr2.switch()
def f2():
print(33)
gr1.switch()
print(44)
# 创建两个协程
gr1 = greenlet.greenlet(f1)
gr2 = greenlet.greenlet(f2)
gr1.switch()
协程存在的意义
单线程实现并发:如果遇到IO操作
就会进行切换
遇到IO就切换 + 协程 == 牛逼起来了。。。
遇到IO就切换 实现:gevent模块
gevent模块(IO切换+协程)
安装:
pip install gevent
示例代码:
########### 协程+IO切换
from gevent import monkey
monkey.patch_all() # 以后代码中遇到IO就会执行greenlet的switch进行切换
import requests
import gevent
def get_page(url):
resp = requests.get(url)
print(url,resp.content.decode('utf8'))
gevent.joinall([
gevent.spawn(get_page,'https://www.python.org/'), # 协程1
gevent.spawn(get_page,'https://www.yahoo.com/'), # 协程2
gevent.spawn(get_page,'https://github.com/'), # 协程3
])
什么是协程?
协程也可以称为”微线程“,就是开发者控制着线程执行流程,控制先执行某段代码然后再切换到另外函数执行代码.... 来回切换
协程可以提高并发吗?
协程本身无法实现并发(甚至性能会降低)
协程+IO切换性能会提高
进程;线程;协程的区别?
- 1.进程是计算器最小资源分配单位
- 2.线程是CPU调度的最小单位
- 3.进程切换需要的资源很最大,效率很低
- 4.线程切换需要的资源一般,效率一般(当然了在不考虑GIL的情况下)
- 5.协程切换任务资源很小,效率高(协程本身并不存在,是程序员通过控制IO操作完成)
- 6.多进程、多线程根据cpu核数不一样可能是并行的,但是协程是在一个线程中 所以是并发
进程:一个运行的程序(代码)就是一个进程,没有运行的代码叫程序,进程是系统资源分配的最小单位,进程拥有自己独立的内存空间,所以进程间数据不共享,开销大。
线程: 调度执行的最小单位,也叫执行路径,不能独立存在,依赖进程存在一个进程至少有一个线程,叫主线程,而多个线程共享内存(数据共享,共享全局变量),从而极大地提高了程序的运行效率。
协程:是一种用户态的轻量级线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。 协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。
区别与联系
多进程的优点是稳定性好,一个子进程崩溃了,不会影响主进程以及其余进程。但是缺点是创建进程的代价非常大,因为操作系统要给每个进程分配固定的资源,并且,操作系统对进程的总数会有一定的限制,若进程过多,操作系统调度都会存在问题,会造成假死状态。
多线程优点是效率较高一些,但是致命的缺点是任何一个线程崩溃都可能造成整个进程的崩溃,因为它们共享了进程的内存资源池。 对于任务数来说,无论是多进程或者多线程,都不能太多。因为操作系统在切换任务时,会有一系列的保护现场措施,这要花费相当的系统资源,若任务过多,则大部分资源都被用做干这些了,结果就是所有任务都做不好,所以操作系统会限制进程的数量。 另外,考虑计算密集型及IO密集型应用程序。对于计算密集型,多任务势必造成资源浪费。对于IO密集型,因为IO速度远低于CPU计算速度,所以使用多任务方式可以大大增大程序运行效率。
协程是python个中另外一种实现多任务的方式,只不过比线程更小占用更小执行单元(理解为需要的资源)。 为啥说它是一个执行单元,因为它自带CPU上下文。这样只要在合适的时机, 我们可以把一个协程 切换到另一个协程。 只要这个过程中保存或恢复 CPU上下文那么程序还是可以运行的。
在实现多任务时, 线程切换从系统层面远不止保存和恢复 CPU上下文这么简单。 操作系统为了程序运行的高效性每个线程都有自己缓存Cache等等数据,操作系统还会帮你做这些数据的恢复操作。 所以线程的切换非常耗性能。但是协程的切换只是单纯的操作CPU的上下文,所以一秒钟切换个上百万次系统都抗的住。
单线程提供并发
- 协程+IO切换:gevent
- 基于事件循环的异步非阻塞框架:Twisted
基于yield实现协程(了解即可)
def f1():
print(1)
yield
print(2)
yield
print(3)
def f2():
print(4)
yield
print(5)
yield
print(6)
v1 =f1()
v2 =f2()
next(v1)
next(v2)
next(v1)
next(v2)
next(v1)
next(v2)
总结
进程,线程,协程的区别 (重点)
gevent
Twisted
异步非阻塞
IO多路复用:可以检测所有的IO请求的状态
典型例子:socket
- Input
- output
三种模式:
select
poll
epoll
以上是关于Python 协程的主要内容,如果未能解决你的问题,请参考以下文章