执行协程
asyncio提供了三种执行协程的机制
-
使用asyncio.run()执行协程(仅限于python3.7以上版本)。此函数总是创建一个新的事件循环,并在最后关闭它。建议将它用作asyncio程序的主入口,如main(),并且只调用一次。
在同一个线程中,当已经有asyncio事件循环在执行时,不能调用此函数。
-
await一个协程。在一个已经运行协程中await另一协程。
import asyncio
async def do_some_work(x):
print("Hello:", x)
return "work is done for {}".format(x)
async def main():
for i in range(5):
result = await do_some_work(i)
print(result)
asyncio.run(main())
Hello: 0
work is done for 0
Hello: 1
work is done for 1
Hello: 2
work is done for 2
Hello: 3
work is done for 3
Hello: 4
work is done for 4
之前使用的是python 3.6版本,可以在外部直接await
await main()
Hello: 0
Hello: 1
Hello: 2
Hello: 3
Hello: 4
Out[34]:
['work is done for 0',
'work is done for 1',
'work is done for 2',
'work is done for 3',
'work is done for 4']
但是在3.7里,就报错。。。
await main()
File "<input>", line 14
SyntaxError: 'await' outside function
- 定义一个事件循环对象loop容器,将task任务扔进事件循环对象中触发。把协程对象交给 loop,协程对象随后会在 loop 里得到运行。
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
loop.run_until_complete(main())
Hello: 0
work is done for 0
Hello: 1
work is done for 1
Hello: 2
work is done for 2
Hello: 3
work is done for 3
Hello: 4
work is done for 4
停止协程
loop启动之后,ctrl+c,run_until_complete会有执行异常。通过asyncio.Task的cancel方法可以取消future。
调用cancel()会引起Task对象向被封装的协程抛出CancelledError异常。当取消行为发生时,如果协程正在等待某个Future对象执行,该Future对象将被取消。
cancelled()方法用于检查某个Task是否已被取消。如果Task封装的协程没有阻止CancelledError异常,且Task确实被取消了,则该方法返回True。
import asyncio
import time
async def do_some_work(x):
print('Hello do_some_work:', x)
try:
await asyncio.sleep(x)
except asyncio.CancelledError:
print('task do_some_work({}) was canceled'.format(x))
raise
print('do_some_work({}) is still active'.format(x))
return "work is done for {}".format(x)
def cancel_task(future):
future.cancel()
print('cancelled the task:', id(future))
async def main(loop):
tasks = []
for i in range(5):
coroutine = do_some_work(i)
task = loop.create_task(coroutine)
tasks.append(task)
return await asyncio.gather(*tasks)
print('start...')
start = time.time()
event_loop = asyncio.new_event_loop()
asyncio.set_event_loop(event_loop)
try:
results = event_loop.run_until_complete(main(event_loop))
for result in results:
print("task result:", result)
except KeyboardInterrupt:
now = event_loop.time()
for task in asyncio.Task.all_tasks():
print('cancelling the task {}: {}'.format(id(task), task.cancel()))
event_loop.stop()
event_loop.run_forever()
finally:
event_loop.close()
end = time.time()
print("total run time: ", end - start)
start...
Hello do_some_work: 0
Hello do_some_work: 1
Hello do_some_work: 2
Hello do_some_work: 3
Hello do_some_work: 4
do_some_work(0) is still active
do_some_work(1) is still active
^Ccancelling the task 2246916857928: True
cancelling the task 2246916861192: True
cancelling the task 2246916858200: False
cancelling the task 2246916860240: True
cancelling the task 2246916861328: True
cancelling the task 2246916860376: False
task do_some_work(2) was canceled
task do_some_work(3) was canceled
task do_some_work(4) was canceled
total run time: 2.0016472339630127
True 表示 cancel 成功。运行程序,不到一秒的时间立马就ctr+c。以上看出 do_some_work(0) 没有cancel成功,因为asyncio.sleep(0) 也就是没有sleep, 所以do_some_work(0)瞬间就完成了,这时候取消为时已晚,其他没有来得及执行的task都成功取消了。
shield
如果一个创建后就不希望被任何情况取消,可以使用asyncio.shield保护任务能顺利完成。
shield方法可以将协程(coroutines),该对象会被自动封装为Task。
loop启动之后,ctrl+c,run_until_complete的执行异常。通过asyncio.Task可以取消future。import asyncioimport timenow = lambda: time.time()async def do_some_work(x): print("Hello:", x) time.sleep(1) return "w...
协程中未处理的异常会向上冒泡,传给 next 函数或 send 方法的调用方(即触发协程的对 象)。下面示例举例说明如何使用之前博客示例中由装饰器定义的 averager 协程。
未处理的异常会导致协程终止
预激协程的装饰器
from inspect import getgeneratorstate
from functools import wraps
def coro...
【作用一】:partial() 函数允许你给一个或多个参数设置固定的值,减少接下来被调用时的参数个数。
【作用二】:partial() 用于固定某些参数,并返回一个新的callable对象。
关于协程的调用步骤
下面将简单介绍asyncio的使用。
????event_loop 事件循环:程序开启一个无限的循环,程序员会把一些函数注册到事件循环上。当满足事件发生的时候,调用相应的协程函数
asyncio是Python 3.4版本引入的标准库,直接内置了对异步IO的支持。
asyncio的编程模型就是一个消息循环。我们从asyncio模块中直接获取一个EventLoop的引用,然后把需要执行的协程扔到EventLoop中执行,就实现了异步IO。
用asyncio实现Hello world代码如下:
import asyncio
@asyncio.coroutine
def hello():
print("Hello world!")
# 异步调用asyncio.sle
一、事件循环EventLoop
事件循环是asyncio的核心,异步任务的运行、任务完成之后的回调、网络IO操作、子进程的运行,都是通过事件循环完成的。在前一篇文章中,已经提到过,在python3.7中,我们甚至完全不用管事件循环,只需要使用高层API,即asyncio中的方法,我们很少直接与事件循环打交道,但是为了更加熟悉asyncio的运行原理,最好还是了解EventLoop的设计原理。
1、事件循环的创建、获取、设置(上文已经介绍过了)
(1)asyncio.get_running_loop(
其实简单的不得了. 弄个线程,在线程里运行一个新的事件循环. 然后调用 run_coroutine_threadsafe 即可.
asyncio基础 :python 异步 asyncio
asyncio.get_event_loop() 默认是主线程的事件循环
每个线程一个事件循环 , 默认情况select循环
下面给出实现:
mport asyncio
def t...
之前爬虫使用的是requests+多线程/多进程,后来随着前几天的深入了解,才发现,对于爬虫来说,真正的瓶颈并不是CPU的处理速度,而是对于网页抓取时候的往返时间,因为如果采用requests+多线程/多进程,他本身是阻塞式的编程,所以时间都花费在了等待网页结果的返回和对爬取到的数据的写入上面。而如果采用非阻塞编程,那么就没有这个困扰。这边首先要理解一下阻塞和非阻塞的区别。
阻塞调用是指调用结果返回之前,当前线程会被挂起(线程进入非可
这个例子定义了两个协程函数,`hello()` 和 `main()`。`hello()` 函数打印出 "Hello",然后等待一秒钟,最后再打印出 "World"。`main()` 函数使用 `asyncio.gather()` 并发运行三个 `hello()` 协程函数。
通过这个例子,我们可以看到使用 `asyncio` 模块,我们可以方便地实现异步编程,从而提高程序的效率和并发性。