python异步协程,python协程的使用场景
本文主要分享Python协同处理的实践。简单来说,co-process是一个更轻量级的线程,它不是由操作系统内核管理,而是完全由程序控制。以下相关介绍,有需要的朋友可以参考一下。
00-1010协同学中的协同学yield用法经典示例生产者-消费者模型(协同学)gevent第三方库协同学支持经典代码asyncio内置库协同学支持关于aiohttp
目录
简单地说,协同进程是一个更轻量级的线程,的进程,它不是由操作系统内核管理,而是完全由程序控制(在用户模式下执行)。协同流程在子程序中是可中断的,然后转向其他子程序,并在适当的时间返回继续执行。
协程的优势?(协同协议)有自己的寄存器环境和堆栈。调度切换时,寄存器上下文和堆栈被保存到其他地方。当切换回来时,先前保存的寄存器环境和堆栈被恢复。直接操作栈基本没有内核切换开销,可以不加锁访问全局变量,所以上下文很快。)
协程
1.协同中的yield通常出现在表达式的右边3360。
x=产量数据
如果yield右侧没有表达式,则默认输出值为None。现在右边有一个表达式,所以返回数据的值。
2.协程可以接受来自调用方法的数据,调用通过send(x)向协程提供数据。同时,send方法包含了next方法,所以程序会继续执行。
3.协同过程的执行可以被中断以执行另一个协同过程。
yield在协程中的用法
代码:
def hello():
数据=mima
而True:
x=产量数据
打印(x)
a=你好()
下一个(a)
data=a.send(hello )
打印(数据)
代码解释:
当程序开始执行时,函数hello将不会实际执行,而是将一个生成器返回给一个。
调用next()方法时,hello函数实际开始执行,print方法执行,while循环继续;
当程序遇到yield关键字时,程序再次被中断。此时,当执行到a . send(“hello”)时,程序将继续从yield关键字,向下执行,然后再次进入while循环。当再次遇到yield关键字时,程序再次中断。
运作过程中的协成四个状态;
GEN_CREATE:等待开始执行GEN_RUNNING:解释器正在yield表达式处执行GEN_SUSPENDED:暂停GEN_CLOSED:执行。
经典示例
导入时间
定义消费者():
r=
而True:
res=收益率r
如果不是res:
打印(开始.)
返回
打印([消费者]消费% s…%分辨率)
时间.睡眠(1)
r=200 OK
def生产(c):
原名的
xt(c)
n = 0
while n<6:
n+=1
print("[PRODUCER] Producing %s ...."%n)
r = c.send(n)
print("[CONSUMER] Consumer return: %s ...."%r)
c.close()
c = consumer()
produce(c)
代码分析:
- 调用next©启动生成器;
- 消费者一旦生产东西,通过c.send切换到消费者consumer执行;
- consumer通过yield关键字获取到消息,在通过yield把结果执行;
- 生产者拿到消费者处理过的结果,继续生成下一条消息;
- 当跳出循环后,生产者不生产了,通过close关闭消费者,整个过程结束;
gevent第三方库协程支持
原理:gevent基于协程的Python网络库,当一个greenlet遇到IO操作(访问网络)自动切换到其他的greenlet等到IO操作完成后,在适当的时候切换回来继续执行。换而言之就是greenlet通过帮我们自动切换协程,保证有greenlet在运行,而不是一直等待IO操作。
经典代码
由于切换时在发生IO操作时自动完成,所以gevent需要修改Python内置库,这里可以打上猴子补丁(用来在运行时动态修改已有的代码,而不需要原有的代码)monkey.patch_all
#!/usr/bin/python2# coding=utf8
from gevent import monkey
monkey.patch_all()
import gevent
import requests
def handle_html(url):
print("Starting %s。。。。" % url)
response = requests.get(url)
code = response.status_code
print("%s: %s" % (url, str(code)))
if __name__ == "__main__":
urls = ["https://www.baidu.com", "https://www.douban.com", "https://www.qq.com"]
jobs = [ gevent.spawn(handle_html, url) for url in urls ]
gevent.joinall(jobs)
运行结果:
结果:3个网络连接并发执行,但是结束的顺序不同。
asyncio内置库协程支持
原理:asyncio的编程模型就是一个消息循环,从asyncio模块中直接获取一个Eventloop(事件循环)的应用,然后把需要执行的协程放入EventLoop中执行,实现异步IO。
经典代码:
import asyncioimport threading
async def hello():
print("hello, world: %s"%threading.currentThread())
await asyncio.sleep(1) #
print(hello, man %s%threading.currentThread())
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait([hello(), hello()]))
loop.close()
代码解析:
- 首先获取一个EventLoop
- 然后将这个hello的协程放进EventLoop,运行EventLoop,它会运行知道future被完成
- hello协程内部执行await asyncio.sleep(1)模拟耗时1秒的IO操作,在此期间,主线程并未等待,而是去执行EventLoop中的其他线程,实现并发执行。
代码结果:
异步爬虫实例:
#!/usr/bin/python3import aiohttp
import asyncio
async def fetch(url, session):
print("starting: %s" % url)
async with session.get(url) as response:
print("%s : %s" % (url,response.status))
return await response.read()
async def run():
urls = ["https://www.baidu.com", "https://www.douban.com", "http://www.mi.com"]
tasks = []
async with aiohttp.ClientSession() as session:
tasks = [asyncio.ensure_future(fetch(url, session)) for url in urls] # 创建任务
response = await asyncio.gather(*tasks) # 并发执行任务
for body in response:
print(len(response))
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(run())
loop.close()
代码解析:
- 创建一个事件循环,然后将任务放到时间循环中;
- run()方法中主要是创建任务,并发执行任务,返回读取到的网页内容;
- fetch()方法通过aiohttp发出指定的请求,以及返回 可等待对象;
(结束输出网址和list中网址的顺序不同,证明协程中异步I/O操作)
关于aiohttp
asyncio实现类TCP、UDP、SSL等协议,aiohttp则是基于asyncio实现的HTTP框架,由此可以用来编写一个微型的HTTP服务器。
代码:
from aiohttp import webasync def index(request):
await asyncio.sleep(0.5)
print(request.path)
return web.Response(body= Hello, World)
async def hello(request):
await asyncio.sleep(0.5)
text = hello, %s%request.match_info[name]
print(request.path)
return web.Response(body=text.encode(utf-8))
async def init(loop):
app = web.Application(loop=loop)
app.router.add_route("GET", "/" , index)
app.router.add_route("GET","/hello/{name}", hello)
srv = await loop.create_server(app.make_handler(), 127.0.0.1, 8000)
print("Server started at http://127.0.0.0.1:8000....")
return srv
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(init(loop))
loop.run_forever()
代码解析:
- 创建一个事件循环,传入到init协程中;
- 创建Application实例,然后添加路由处理指定的请求;
- 通过loop创建TCP服务,最后启动事件循环;
到此这篇关于Python协程实践分享的文章就介绍到这了,更多相关Python协程内容请搜索盛行IT软件开发工作室以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT软件开发工作室!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。