python_协程、从生成器到协程的发展历程、gevent第三方库实现协程、内置asycio实现协程

一:协程

概念:  

协程:
1)并发:JMeter并发100个请求。
2)并行:2个进程分别在2个cpu上并行运行
3)同步:IO操作,耗时,等待操作完毕
4)异步:不等待操作完毕
5)并发是实现异步
实现异步(并发)的方法有:多线程、协程
(1)多线程:CPU调度多个线程 (由内核决定的)
(2)协程:开发人员调度多个任务(开发人员:指的是用户)
举栗:有两个函数 work1() ,work2(),当work1阻塞的时候运行work2,work2阻塞的时候运行work1
要实现这个例子:需要有 1)挂起当前状态(暂停) 2)激活挂起的状态(恢复) 的能力

 

核心思想:  

协程的核心思想:
为了实现异步io
若干个协程任务,当某个任务遇到阻塞时,自动切换到非阻塞的任务上
阻塞: io阻塞。如:input("请输入一个数: "),磁盘io(写数据是需要时间的),网络io(网络请求数据时需要时间的)
用户态:切换不需要CPU调度
核心态:线程切换,进程切换,核心态, 切换需要cpu调度

 

二。从生成器到协程:python在3.5版本之前是没有协程这个概念的,生产器是在python2.3版本中引入的,使用生成器实现协程是在 python2.5 可以进行的。

发展历程:

  

从生成器到协程:从Python2到Python3,协程经历了翻天覆地的变化。
简单的生成器:
https:www.python.org/dev/peps/pep-0255/
Python2.3中,加入了新的关键字:yield
在PE255中,引入了yield表达式
规定yield语句只能在函数中使用。包含yield语句的函数被称为生成器函数
当执行到yield语句时,函数的状态会被冻结(挂起所有状态,如:局部变量、指令指针、堆栈状态等),以便下载
next时恢复状态继续执行。
通过生成器实现协程:
协程的底层架构是在PEP 342中定义,在Python2.5实现的。
实现思想:使用yield挂起生成器,使用send方法激活生成器就具备实现协程功能
执行generator.send(None) 完全等同于调用生成器的 next方法。使用其他参数调用send也有同样的效果, 的是,当前生成器表达式产生的值会不一样。
参考资料:PEP 342 Coroutines via Enhanced Generators https://www.python.org/dev/peps/pep-0342/

协程的演变:
Python3.3增加了 yield from 语法,使用调用嵌套生成器变得简单
举栗:
def f():
yield from [1,2,3]
Python3.5 加入了关键字 async 和 await,将生成器和协程全部分开
参考资料:
PEP 380 Syntax for Delegating to a Subgenerator https://www.python.org/dev/peps/pep-0380/
PEP 525 Asynchronous Generators https://www.python.org/dev/peps/pep-0525/

 

生成器实现协程:

  

"""
也就是使用生成器实现多任务
"""

import time

def work1():
for i in range(5):
print("work1:函数运行中")
time.sleep(1)
yield

def work2():
for i in range(5):
print("work2:函数运行中")
time.sleep(1)
yield


def calc_time(func):
def wrap(*args, **kwargs):
start = time.time()
func(*args, **kwargs)
end = time.time()
print(f"耗时{end - start:.2f}秒")
return wrap

@calc_time
def main():
g1 = work1()
g2 = work2()
while True:
try:
next(g1) #使用迭代控制实现协程
next(g2)
except StopIteration:
break
if __name__ == '__main__':
main()

  

运行结果:

python_协程、从生成器到协程的发展历程、gevent第三方库实现协程、内置asycio实现协程

 

 

二。gevent

实现方法一:通过gevent.time()实现协程

"""
也就是使用生成器实现多任务:
注意:
1.gevent 如果不适用阻塞,主程序结束,子程序也会结束(子程序==线程)
"""
#1,gevent 协程方法一,使用gevent.time()实现协程
import time
import gevent
def work1():
for i in range(5):
print("work1:函数运行中")
gevent.sleep(1)


def work2():
for i in range(5):
print("work2:函数运行中")
gevent.sleep(1)


def calc_time(func):
def wrap(*args, **kwargs):
start = time.time()
func(*args, **kwargs)
end = time.time()
print(f"耗时{end - start:.2f}秒")
return wrap

@calc_time
def main():
g1 = gevent.spawn(work1)
g2 = gevent.spawn(work2)
g1.join()
g2.join()


if __name__ == '__main__':
main()

运行结果:

python_协程、从生成器到协程的发展历程、gevent第三方库实现协程、内置asycio实现协程

 

 

实现方法二:通过打补丁的方式实现协程(导入monkey模块中的patch_all()方法)

"""
也就是使用生成器实现多任务:
注意:
1.gevent 如果不适用阻塞,主程序结束,子程序也会结束(子程序==线程)
"""
#1,gevent 协程方法一,使用gevent.time()实现协程
import time
import gevent
from gevent import monkey
monkey.patch_all()

#2.gevent,协程使用方法二 打补丁,导入monkey模块中的patch_all()方法 。导入: from gevent import monkey; monkey.patch_all()
def work3():
for i in range(5):
print("work3:函数运行中")
time.sleep(1)


def work4():
for i in range(5):
print("work4:函数运行中")
time.sleep(1)


def calc_time(func):
def wrap(*args, **kwargs):
start = time.time()
func(*args, **kwargs)
end = time.time()
print(f"耗时{end - start:.2f}秒")
return wrap


@calc_time
def main2():
g3 = gevent.spawn(work3)
g4 = gevent.spawn(work4)
g3.join()
g4.join()

if __name__ == '__main__':
main2()

运行结果:

python_协程、从生成器到协程的发展历程、gevent第三方库实现协程、内置asycio实现协程

 

 

三。asycio

"""
python3.5之后可用
"""
import time
import asyncio #异步IO库,单线程实现并发 --协程


#async 关键字包裹 await 关键字结束

async def work1():
for i in range(5):
print(f"work1:函数运行")
await asyncio.sleep(1)


async def work2():
for i in range(5):
print(f"work2:函数运行")
await asyncio.sleep(1)


def calc_time(func):
def wrap(*args, **kwargs):
start = time.time()
func(*args, **kwargs)
end = time.time()
print(f"耗时{end - start:.2f}秒")
return wrap


async def main():
task1 = asyncio.create_task(work1()) #任务一
task2 = asyncio.create_task(work2()) # 任务二
await task1
await task2
if __name__ == '__main__':
start = time.time()
asyncio.run(main())
end = time.time()
print(f"耗时{end - start:.2f}秒")

运行结果:

python_协程、从生成器到协程的发展历程、gevent第三方库实现协程、内置asycio实现协程

 

上一篇:*黑客分享的30个极简Python代码,拿走就能用!


下一篇:C#中?、??、?:的使用