Python 网络与并发编程(四)

协程Coroutines

协程,全称是“协同程序”,用来实现任务协作。是一种在线程中,比线程更加轻量级的存在,由程序员自己写程序来管理。
当出现IO阻塞时,CPU一直等待IO返回,处于空转状态。这时候用协程,可以执行其他任务。当IO返回结果后,再回来处理数据。充分利用了IO等待的时间,提高了效率。

协程的核心(控制流的让出和恢复)

1每个协程有自己的执行栈,可以保存自己的执行现场
2 可以由用户程序按需创建协程(比如:遇到io操作),协程“主动让出(yield)”执行权时候,会保存执行现场(保存中断时的寄存器上下文和栈),然后切换到其他协程
3 协程恢复执行(resume)时,根据之前保存的执行现场恢复到中断前的状态,继续执行,这样就通过协程实现了轻量的由用户态调度的多任务模型

协程和多线程比较

比如,有3个任务需要完成,每个任务都在等待I/O操作时阻塞自身。
在这里插入图片描述
1 在单线程同步模型中,任务按照顺序执行。如果某个任务因为I/O而阻塞,其他所有的任务都必须等待,直到它完成之后它们才能依次执行。

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

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

协程的优点

1 由于自身带有上下文和栈,无需线程上下文切换的开销,属于程序级别的切换,操作系统完全感知不到,因而更加轻量级;
2 无需原子操作的锁定及同步的开销;
3 方便切换控制流,简化编程模型
4 单线程内就可以实现并发的效果,最大限度地利用cpu,且可扩展性高,成本低(注:一个CPU支持上万的协程都不是问题。所以很适合用于高并发处理)

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

协程的缺点

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

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

asyncio实现协程(重点)

1 正常的函数执行时是不会中断的,所以你要写一个能够中断的函数,就需要加 asyncasync 用来声明一个函数为异步函数,异步函数的特点是能在函数执行过程中挂起,去执行其他异步函数,等到挂起条件(假设挂起条件是sleep(5) )消失后,也就是5秒到了再回来执行
2 await 用来用来声明程序挂起,比如异步程序执行到某一步时需要等待的时间很长,就将此挂
起,去执行其他的异步程序。
3 asyncio 是python3.5之后的协程模块,是python实现并发重要的包,这个包使用事件循环驱动实现并发。

不使用协程,耗时6秒

#coding=utf-8
import time
def func1():
	for i in range(3):
		print(f'北京:第{i}次打印啦')
		time.sleep(1)
	return "func1执行完毕"
def func2():
	for k in range(3):
		print(f'上海:第{k}次打印了')
		time.sleep(1)
	return "func2执行完毕"
def main():
	func1()
	func2()
if __name__ == '__main__':
	start_time = time.time()
	main()
	end_time = time.time()
	print(f"耗时{end_time-start_time}") #不使用协程,耗时6秒


使用协程,耗时3秒

#coding=utf-8
import asyncio
import time
async def func1(): #async表示方法是异步的
	for i in range(3):
		print(f'北京:第{i}次打印啦')
		await asyncio.sleep(1)
	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(),func2())
	#await异步执行func1方法
	#返回值为函数的返回值列表,本例为["func1执行完毕", "func2执行完毕"]
	print(res)
if __name__ == '__main__':
	start_time = time.time()
	asyncio.run(main())
	end_time = time.time()
	print(f"耗时{end_time-start_time}") #耗时3秒,效率极大提高
  • 20
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

weixin_44006060

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值