在IO操作的过程中,当前线程被挂起,而其他需要CPU执行的代码就无法被当前线程执行了。
我们可以使用多线程或者多进程来并发执行代码,为多个用户服务。 但是,一旦线程数量过多,CPU的时间就花在线程切换上了,真正运行代码的时间就少了,结果导致性能严重下降。 异步IO:当代码需要执行一个耗时的IO操作时,它只发出IO指令,并不等待IO结果,然后就去执行其他代码了。一段时间后,当IO返回结果时,再通知CPU进行处理。 对于大多数IO密集型的应用程序,使用异步IO将大大提升系统的多任务处理能力。1. 异步IO
1.1 协程
协程,又称微线程,纤程。英文名Coroutine。
子程序(函数)调用是通过栈实现的,一个线程就是执行一个子程序。 协程的执行过程中,在子程序内部可中断,然后转而去执行别的子程序,在适当的时候再回来接着执行。Python对协程的支持是通过生成器实现的。 在生成器中,我们不但可以通过for
循环来迭代,还可以不断调用next()
函数获取由yield语句返回的下一个值。但是Python的yield
不但可以返回一个值,它还可以接收调用者发出的参数。 def consumer(): r = '' while True: n = yield r if not n: return print('[CONSUMER] Consuming %s...' % n) r = '200 OK'def produce(c): c.send(None) n = 0 while n < 5: n = n + 1 print('[PRODUCER] Producing %s...' % n) r = c.send(n) print('[PRODUCER] Consumer return: %s' % r) c.close()c = consumer()produce(c)
[PRODUCER] Producing 1...[CONSUMER] Consuming 1...[PRODUCER] Consumer return: 200 OK[PRODUCER] Producing 2...[CONSUMER] Consuming 2...[PRODUCER] Consumer return: 200 OK[PRODUCER] Producing 3...[CONSUMER] Consuming 3...[PRODUCER] Consumer return: 200 OK[PRODUCER] Producing 4...[CONSUMER] Consuming 4...[PRODUCER] Consumer return: 200 OK[PRODUCER] Producing 5...[CONSUMER] Consuming 5...[PRODUCER] Consumer return: 200 OK
1.2 asyncio
asyncio的编程模型是一个消息循环。我们从asyncio模块中直接获取一个EventLoop的引用,然后把需要执行的协程扔到EventLoop中执行,就实现了异步IO。
import asyncio@asyncio.coroutinedef hello(): print("Hello world!") # 异步调用asyncio.sleep(1): r = yield from asyncio.sleep(1) print("Hello again!")# 获取EventLoop:loop = asyncio.get_event_loop()# 执行coroutineloop.run_until_complete(hello())loop.close()
@asyncio.coroutine
把一个生成器标记为协程类型,然后,我们就把这个协程扔到EventLoop中执行。
import threadingimport asyncio@asyncio.coroutinedef hello(): print('Hello world! (%s)' % threading.currentThread()) yield from asyncio.sleep(1) print('Hello again! (%s)' % threading.currentThread())loop = asyncio.get_event_loop()tasks = [hello(), hello()] # 封装两个协程loop.run_until_complete(asyncio.wait(tasks))loop.close()# Hello world! (<_MainThread(MainThread, started 9700)>)# Hello world! (<_MainThread(MainThread, started 9700)>)# Hello again! (<_MainThread(MainThread, started 9700)>)# Hello again! (<_MainThread(MainThread, started 9700)>)
1.3 async/await
import asyncioasync def hello(): print("Hello world!") r = await asyncio.sleep(1) print("Hello again!") # 获取EventLoop:loop = asyncio.get_event_loop()# 执行coroutineloop.run_until_complete(hello())loop.close()
1.4 aiohttp
import asynciofrom aiohttp import webasync def index(request): await asyncio.sleep(0.5) return web.Response(body='Index
'.encode('utf-8'), content_type='text/html')async def hello(request): await asyncio.sleep(0.5) text = 'hello, %s!
' % request.match_info['name'] return web.Response(body=text.encode('utf-8'), content_type='text/html')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.1:8000...') return srvloop = asyncio.get_event_loop()loop.run_until_complete(init(loop))loop.run_forever()
参考资料: