异步
一.协程
协程,又称微线程,纤程。英文名Coroutine。一句话说明什么是线程:协程是一种用户态的轻量级线程。
线程是系统级别的,它们是由操作系统调度;协程是程序级别的,由程序员根据需要自己调度。我们把一个线程中的一个个函数叫做子程序,那么子程序在执行过程中可以中断去执行别的子程序;别的子程序也可以中断回来继续执行之前的子程序,这就是协程。也就是说同一线程下的一段代码<1>执行着执行着就可以中断,然后跳去执行另一段代码,当再次回来执行代码块<1>的时候,接着从之前中断的地方开始执行。
协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈。因此:协程能保留上一次调用时的状态(即所有局部状态的一个特定组合),每次过程重入时,就相当于进入上一次调用的状态,换种说法:进入上一次离开时所处逻辑流的位置。
1.yield实现:
yield不但可以返回一个值,它还可以接收调用者发出的参数
def consumer(): print('开始消费了') ret = '' while True: producter = yield ret if not producter: return print('消费了%s' % producter) ret = '200 ok' def produce(consu): # 启动生成器,第一次必须用None <==> consumer.__next__() consu.send(None) n = 0 while n < 5: n += 1 print('生产了苹果%d' % n) ret = consu.send('苹果%d' % n) print('消费者返回:%s' % ret) consu.close() c = consumer() produce(c)
执行流程:
首先调用consu.send(None)启动生成器;
然后,一旦生产了东西,通过consu.send(n)切换到consumer执行;
consumer通过yield拿到消息,处理,又通过yield把结果传回;
produce拿到consumer处理的结果,继续生产下一条消息;
produce决定不生产了,通过c.close()关闭consumer,整个过程结束。
2.其余还有第三方包greenlet和gevent实现
二.asyncio
asyncio的编程模型就是一个消息循环
import threading import asyncio @asyncio.coroutine def hello(): print('Hello world! (%s)' % threading.currentThread()) # 模拟耗时操作 yield from asyncio.sleep(1) print('Hello again! (%s)' % threading.currentThread()) # 获取EventLoop: loop = asyncio.get_event_loop() tasks = [hello(), hello()] # 执行coroutine loop.run_until_complete(asyncio.wait(tasks)) loop.close()
三.async/await
import asyncio #async申明这是一个异步函数, await用于挂起自身,执行耗时操作 async def get(): await asyncio.sleep(1) return 100 async def hello(): print('开始了') # 模拟耗时操作 a = await get() print('结束了%s' % a) loop = asyncio.get_event_loop() tasks = [hello(), hello()] loop.run_until_complete(asyncio.wait(tasks)) loop.close()
四.aiohttp
aiohttp是基于asyncio实现的HTTP框架
异步简单爬虫示例:
import asyncio import aiohttp get_contents = [] async def html(url): headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36'} async with aiohttp.ClientSession() as session: async with session.get(url, headers=headers, timeout=1, verify_ssl=False) as r: body = await r.text() get_contents.append(body) loop = asyncio.get_event_loop() tasks = [html('http://www.baidu.com'), html('http://www.163.com')] loop.run_until_complete(asyncio.wait(tasks)) loop.close() print(len(get_contents))
输出:
2