13.并发编程之协程
Posted journeyer-xsh
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了13.并发编程之协程相关的知识,希望对你有一定的参考价值。
一、协程基础
cpython下多个线程不能利用多核:规避了所有的io操作的单线程。
协程
- 操作系统不可见
- 协程本质就是一条线程,多个任务在一条线程上来回切换,来规避io操作,降低了线程上的io操作降到最低。
4 cpu:可以接受5个进程,20个线程,协程500
切换并规避IO的模块
- gevent 利用 greenlet 底层模块完成的切换 + 自动规避IO的功能。
- asyncio 利用 yield 底层语法完成的切换 + 自动规避IO的功能。
- tornado 异步的web框架
- yield from 更好的实现协程
- send 更好的实现协程
- asyncio模块,基于python原生的协程的概念正式被成立
- 特殊的在python中提供协程的功能的关键字,aysnc await
进程、线程、协程之间区别:
进程 | 数据隔离 | 数据不安全 | 操作系统级别 | 开销最大 | 能利用多核 | |
线程 | 数据共享 | 数据不安全 | 操作系统级别 | 开销较小 | 不能利用多核 | 一些和文件操作相关的io只有操作系统能感知到 |
协程 | 数据共享 | 数据安全 | 用户级别 | 开销非常小 | 不能利用多核 | 协程的所有切换都基于用户只有在用户级别能感知到的操作才会用协程模块做切换 |
用户级别的协程有什么好处?减轻操作系统的负担,一条线程开了多个协程,那么给操作系统的印象是线程很忙,这样能多争取一些时间来被cpu执行,程序的效率提高了。
二、gevent模块
协程之间是并发的,使用time.sleep()就不是并发的了。
import gevent
def func(): # 带有io操作的内容卸载函数中,然后提交func给gevent
print(‘start func‘)
gevent.sleep(1)
print(‘end func‘)
g1 = gevent.spawn(func)
g2 = gevent.spawn(func)
g3 = gevent.spawn(func)
gevent.joinall([g1, g2, g3])
# g1.join() # 阻塞,知道协程g1任务执行结束
# g2.join()
# g3.join()
from gevnet import monkey必须写在前面,不然time.sleep()就是同步的了。
from gevent import monkey
monkey.patch_all()
import gevent
import time
def func(): # 带有io操作的内容卸载函数中,然后提交func给gevent
print(‘start func‘)
time.sleep(1)
print(‘end func‘)
g1 = gevent.spawn(func)
g2 = gevent.spawn(func)
g3 = gevent.spawn(func)
gevent.joinall([g1, g2, g3])
检测一个模块在gevent处能不能规避io?
import socket
print(socket.socket) # 在patch_all 之前打印一次
from gevent import monkey # gevent 如何检测是否能规避某个模块的io操作?
monkey.patch_all()
import socket
import gevent
print(socket.socket) # 在path_all 之后打印一次,如果两次不一样,那么就说明能规避io操作
三、asyncio模块
import asyncio
async def func(name):
print(‘start‘, name)
# await 可能会发生阻塞的方法
# await 关键字必须卸载一个asyncio函数中
await asyncio.sleep(1)
print(‘end‘)
loop = asyncio.get_event_loop()
# 同步
# loop.run_until_complete(func(‘an‘))
# 异步
loop.run_until_complete(asyncio.wait([func(‘an‘), func(‘bn‘)]))
以上是关于13.并发编程之协程的主要内容,如果未能解决你的问题,请参考以下文章