Python asyncio 模块

Python 3.4
asyncio是Python 3.4版本引入的标准库,直接内置了对异步IO的支持。

asyncio的编程模型就是一个消息循环。我们从asyncio模块中直接获取一个EventLoop的引用,然后把需要执行的协程扔到EventLoop中执行,就实现了异步IO。

用asyncio实现Hello world代码如下:

import asyncio

@asyncio.coroutine
def hello():
    print("Hello world!")
    # 异步调用asyncio.sleep(1):
    r = yield from asyncio.sleep(1)
    print("Hello again!")

# 获取EventLoop:
loop = asyncio.get_event_loop()
# 执行coroutine
loop.run_until_complete(hello())
loop.close()
@asyncio.coroutine把一个generator标记为coroutine类型,然后,我们就把这个coroutine扔到EventLoop中执行。 hello()会首先打印出Hello world!,然后,yield from语法可以让我们方便地调用另一个generator。由于asyncio.sleep()也是一个coroutine,所以线程不会等待asyncio.sleep(),而是直接中断并执行下一个消息循环。当asyncio.sleep()返回时,线程就可以从yield from拿到返回值(此处是None),然后接着执行下一行语句。 把asyncio.sleep(1)看成是一个耗时1秒的IO操作,在此期间,主线程并未等待,而是去执行EventLoop中其他可以执行的coroutine了,因此可以实现并发执行。

我们用Task封装两个coroutine试试: 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()) loop = asyncio.get_event_loop() tasks = [hello(), hello()] loop.run_until_complete(asyncio.wait(tasks)) loop.close() 观察执行过程: Hello world! (<_MainThread(MainThread, started 140735195337472)>) Hello world! (<_MainThread(MainThread, started 140735195337472)>) (暂停约1秒) Hello again! (<_MainThread(MainThread, started 140735195337472)>) Hello again! (<_MainThread(MainThread, started 140735195337472)>) 由打印的当前线程名称可以看出,两个coroutine是由同一个线程并发执行的。 如果把asyncio.sleep()换成真正的IO操作,则多个coroutine就可以由一个线程并发执行。 参考:https://www.liaoxuefeng.com/wiki/1016959663602400/1017970488768640
python3.5


关于asyncio的一些关键字的说明:

event_loop 事件循环:程序开启一个无限循环,把一些函数注册到事件循环上,当满足事件发生的时候,调用相应的协程函数

coroutine 协程:协程对象,指一个使用async关键字定义的函数,它的调用不会立即执行函数,而是会返回一个协程对象。协程对象需要注册到事件循环,由事件循环调用。

task 任务:一个协程对象就是一个原生可以挂起的函数,任务则是对协程进一步封装,其中包含了任务的各种状态

future: 代表将来执行或没有执行的任务的结果。它和task上没有本质上的区别

async/await 关键字:python3.5用于定义协程的关键字,async定义一个协程,await用于挂起阻塞的异步调用接口。


import asyncio
import time

now = lambda :time.time()

async def do_some_work(x):
    print("waiting:",x)
    # await 后面就是调用耗时的操作
    await asyncio.sleep(x)
    return "Done after {}s".format(x)

start = now()

coroutine = do_some_work(2)
loop = asyncio.get_event_loop()
task = asyncio.ensure_future(coroutine)
loop.run_until_complete(task)

print("Task ret:", task.result())
print("Time:", now() - start)

参考:https://www.cnblogs.com/zhaof/p/8490045.html
Python3.7

传统的asyncio异步事件循环
在Python3.7以前的版本,调用异步函数前要先调用asyncio.get_event_loop()函数获取事件循环loop对象,然后通过不同的策略调用loop.run_forever()方法或者loop.run_until_complete()方法执行异步函数。一个典型的例子是这样的。

import asyncio
import random
import datetime

async def wait_and_echo(content):
    wait = random.randint(0, 10)
    print(f'print {content} after {wait} seconds')
    await asyncio.sleep(wait)
    print(f'{content} printed at {datetime.datetime.utcnow().strftime("%H:%M:%S ")}')

async def main():
    await asyncio.gather(*[wait_and_echo(x) for x in range(10)])

loop = asyncio.get_event_loop()
tasks = [wait_and_echo(x) for x in range(10)]
loop.run_until_complete(asyncio.gather(*tasks))
运行结果如:

print 0 after 9 seconds
print 1 after 0 seconds
print 2 after 7 seconds
print 3 after 2 seconds
print 4 after 8 seconds
print 5 after 3 seconds
print 6 after 2 seconds
print 7 after 9 seconds
print 8 after 1 seconds
print 9 after 1 seconds
1 printed at 05:15:26
8 printed at 05:15:27
9 printed at 05:15:27
6 printed at 05:15:28
3 printed at 05:15:28
5 printed at 05:15:29
2 printed at 05:15:33
4 printed at 05:15:34
0 printed at 05:15:35
7 printed at 05:15:35
使用asyncio.run()函数执行异步函数
asyncio.run()函数的官方文档是这样子的:

Signature: asyncio.run(main, *, debug=False)
Docstring:
Run a coroutine.

This function runs the passed coroutine, taking care of
managing the asyncio event loop and finalizing asynchronous
generators.

This function cannot be called when another asyncio event loop is
running in the same thread.

If debug is True, the event loop will be run in debug mode.

This function always creates a new event loop and closes it at the end.
It should be used as a main entry point for asyncio programs, and should
ideally only be called once.

Example:

    async def main():
        await asyncio.sleep(1)
        print('hello')

    asyncio.run(main())
File:      c:\users\pc\appdata\local\programs\python\python37\lib\asyncio\runners.py
Type:      function
使用Python3.7中的新APIasyncio.run(),上述例子可以改写为:

import asyncio
import random
import datetime

async def wait_and_echo(content):
    wait = random.randint(0, 10)
    print(f'print {content} after {wait} seconds')
    await asyncio.sleep(wait)
    print(f'{content} printed at {datetime.datetime.utcnow().strftime("%H:%M:%S ")}')

async def main():
    await asyncio.gather(*[wait_and_echo(x) for x in range(10)])

asyncio.run(main())
运行结果并没有差异。

 

  

 

posted @ 2019-05-08 14:25  Cool·  阅读(407)  评论(0编辑  收藏  举报