一.协程
协程,又称微线程,纤程。英文名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