|
1 | 1 | 使用Asyncio管理事件循环
|
2 | 2 | =======================
|
| 3 | + |
| 4 | +Python的Asyncio模块提供了管理事件、协程、任务和线程的方法,以及编写并发代码的原语。此模块的主要组件和概念包括: |
| 5 | + |
| 6 | +- **事件循环**: 在Asyncio模块中,每一个进程都有一个事件循环。 |
| 7 | +- **协程**: 这是子程序的泛化概念。协程可以在执行期间暂停,这样就可以等待外部的处理(例如IO)完成之后,从之前暂停的地方恢复执行。 |
| 8 | +- **Futures**: 定义了 ``Future`` 对象,和 ``concurrent.futures`` 模块一样,表示尚未完成的计算。 |
| 9 | +- **Tasks**: 这是Asyncio的子类,用于封装和管理丙型模式下的协程。 |
| 10 | + |
| 11 | +本节中重点讨论事件,事实上,异步编程的上下文中,事件无比重要。因为事件的本质就是异步。 |
| 12 | + |
| 13 | +什么是事件循环 |
| 14 | +-------------- |
| 15 | + |
| 16 | +在计算系统中,可以产生事件的实体叫做事件源,能处理事件的实体叫做事件处理者。此外,还有一些第三方实体叫做事件循环。它的作用是管理所有的事件,在整个程序运行过程中不断循环执行,追踪事件发生的顺序将它们放到队列中,当主线程空闲的时候,调用相应的事件处理者处理事件。最后,我们可以通过下面的伪代码来理解事件循环::: |
| 17 | + |
| 18 | + while (1) { |
| 19 | + events = getEvents(); |
| 20 | + for (e in events) |
| 21 | + processEvent(e); |
| 22 | + } |
| 23 | + |
| 24 | +所有的时间都在 ``while`` 循环中捕捉,然后经过事件处理者处理。事件处理的部分是系统唯一活跃的部分,当一个事件处理完成,流程继续处理下一个事件。 |
| 25 | + |
| 26 | +|ready| |
| 27 | +------- |
| 28 | + |
| 29 | +Asyncio提供了一下方法来管理事件循环: |
| 30 | + |
| 31 | +- ``loop = get_event_loop()``: 得到当前上下文的事件循环。 |
| 32 | +- ``loop.call_later(time_delay, callback, argument)``: 延后 ``time_delay`` 秒再执行 ``callback`` 方法。 |
| 33 | +- ``loop.call_soon(callback, argument)``: 尽可能快调用 ``callback``, ``call_soon()`` 函数结束,主线程回到事件循环之后就会马上调用 ``callback`` 。 |
| 34 | +- ``loop.time()``: 以float类型返回当前时间循环的内部时间。 |
| 35 | +- ``asyncio.set_event_loop()``: 为当前上下文设置事件循环。 |
| 36 | +- ``asyncio.new_event_loop()``: 根据此策略创建一个新的时间循环并返回。 |
| 37 | +- ``loop.run_forever()``: 在调用 ``stop()`` 之前将一直运行。 |
| 38 | + |
| 39 | +|how| |
| 40 | +----- |
| 41 | + |
| 42 | +下面的代码中,我们将展示如何使用Asyncio库提供的时间循环创建异步模式的应用。 :: |
| 43 | + |
| 44 | + import asyncio |
| 45 | + import datetime |
| 46 | + import time |
| 47 | + |
| 48 | + def function_1(end_time, loop): |
| 49 | + print ("function_1 called") |
| 50 | + if (loop.time() + 1.0) < end_time: |
| 51 | + loop.call_later(1, function_2, end_time, loop) |
| 52 | + else: |
| 53 | + loop.stop() |
| 54 | + |
| 55 | + def function_2(end_time, loop): |
| 56 | + print ("function_2 called ") |
| 57 | + if (loop.time() + 1.0) < end_time: |
| 58 | + loop.call_later(1, function_3, end_time, loop) |
| 59 | + else: |
| 60 | + loop.stop() |
| 61 | + |
| 62 | + def function_3(end_time, loop): |
| 63 | + print ("function_3 called") |
| 64 | + if (loop.time() + 1.0) < end_time: |
| 65 | + loop.call_later(1, function_1, end_time, loop) |
| 66 | + else: |
| 67 | + loop.stop() |
| 68 | + |
| 69 | + def function_4(end_time, loop): |
| 70 | + print ("function_5 called") |
| 71 | + if (loop.time() + 1.0) < end_time: |
| 72 | + loop.call_later(1, function_4, end_time, loop) |
| 73 | + else: |
| 74 | + loop.stop() |
| 75 | + |
| 76 | + loop = asyncio.get_event_loop() |
| 77 | + |
| 78 | + end_loop = loop.time() + 9.0 |
| 79 | + loop.call_soon(function_1, end_loop, loop) |
| 80 | + # loop.call_soon(function_4, end_loop, loop) |
| 81 | + loop.run_forever() |
| 82 | + loop.close() |
| 83 | + |
| 84 | +运行结果如下::: |
| 85 | + |
| 86 | + python3 event.py |
| 87 | + function_1 called |
| 88 | + function_2 called |
| 89 | + function_3 called |
| 90 | + function_1 called |
| 91 | + function_2 called |
| 92 | + function_3 called |
| 93 | + function_1 called |
| 94 | + function_2 called |
| 95 | + function_3 called |
| 96 | + |
| 97 | +|work| |
| 98 | +------ |
| 99 | + |
| 100 | +在这个例子中,我们定义了三个异步的任务,相继执行,入下图所示的顺序。 |
| 101 | + |
| 102 | +.. image:: ../images/task-execution.png |
| 103 | + |
| 104 | +首先,我们要得到这个事件循环::: |
| 105 | + |
| 106 | + loop = asyncio.get_event_loop() |
| 107 | + |
| 108 | +然后我们通过 ``call_soon`` 方法调用了 ``function_1()`` 函数。 :: |
| 109 | + |
| 110 | + end_loop = loop.time() + 9.0 |
| 111 | + loop.call_soon(function_1, end_loop, loop) |
| 112 | + |
| 113 | +让我们来看一下 ``function_1()`` 的定义::: |
| 114 | + |
| 115 | + def function_1(end_time, loop): |
| 116 | + print ("function_1 called") |
| 117 | + if (loop.time() + 1.0) < end_time: |
| 118 | + loop.call_later(1, function_2, end_time, loop) |
| 119 | + else: |
| 120 | + loop.stop() |
| 121 | + |
| 122 | +这个函数通过以下参数定义了应用的异步行为: |
| 123 | + |
| 124 | +- ``end_time``: 定义了 ``function_1()`` 可以运行的最长时间,并通过 ``call_later`` 方法传入到 ``function_2()`` 中作为参数 |
| 125 | +- ``loop``: 之前通过 ``get_event_loop()`` 方法得到的事件循环 |
| 126 | + |
| 127 | +``function_1()`` 的任务非常简单,只是打印出函数名字。当然,里面也可以写非常复杂的操作。 :: |
| 128 | + |
| 129 | + print ("function_1 called") |
| 130 | + |
| 131 | +任务执行结束之后,它将会比较 ``loop.time()`` +1s和设定的运行时间,如果没有超过,使用 ``call_later`` 在1秒之后执行 ``function_2()`` 。 :: |
| 132 | + |
| 133 | + if (loop.time() + 1.0) < end_time: |
| 134 | + loop.call_later(1, function_2, end_time, loop) |
| 135 | + else: |
| 136 | + loop.stop() |
| 137 | + |
| 138 | +``function_2()`` 和 ``function_3()`` 的作用类似。 |
| 139 | + |
| 140 | +如果运行的时间超过了设定,时间循环终止。 :: |
| 141 | + |
| 142 | + loop.run_forever() |
| 143 | + loop.close() |
0 commit comments