Python教程-Python 事件驱动编程
在本教程中,我们将学习事件驱动编程以及我们可以使用的 Python 模块(Asyncio)来进行 Python 事件驱动编程。
事件驱动编程
最终,程序的流程取决于事件,而侧重于事件的编程称为事件驱动编程。我们之前只处理了并行或顺序模型,但现在我们将讨论异步模型。遵循事件驱动编程概念的编程模型称为异步模型。事件驱动编程的工作取决于程序中发生的事件。
除此之外,它还取决于程序的事件循环,它始终监听程序中的新事件。一旦在程序中启动事件循环,那么只有事件将决定何时执行以及以何种顺序执行。
查看以下事件循环的流程图,以了解事件驱动编程中事件的工作原理:
Asyncio - Python 事件驱动编程模块
Asyncio 模块在 Python 3.4 版本中引入,可以在后续版本的 Python 上使用。Asyncio 模块提供了一个非常好的基础设施,用于编写并发代码,使用程序中的协程进行单线程执行。
在 Python 的 asyncio 模块中,执行事件驱动编程时使用了以下不同概念:
- 事件循环
- Futures(未来对象)
- 协程
- @asyncio.coroutine 装饰器
- 任务
- 传输
- 协议
让我们详细了解 asyncio 模块中使用的所有这些不同概念,以及它们在事件驱动编程中的工作原理。
事件循环
事件循环是 asyncio 模块的功能,用于处理计算程序中发生的所有事件。事件循环就像整个程序执行的往返方式,它还会跟踪已执行和新进入的事件。Asyncio 模块的一个主要优势之一是它允许每个进程中只有一个事件循环。
在 asyncio 模块中,我们可以使用一些方法来管理代码中的事件循环。以下是 asyncio 模块中提供的一些方法。
- time() - 我们可以使用此方法根据事件循环中的内部时钟返回当前时间给用户。
- loop = get_event_loop() - 通过使用此方法,我们将根据程序中当前执行的上下文获取事件循环。
- call_soon(CallbackFunction, ArgumentGiven) - 使用此函数,我们可以安排尽快调用回调函数。给定在参数中的回调函数将在控制返回到事件循环并在 call_soon() 返回之后调用。
- call_later(time_to_delayed, CallbackFunction, ArgumentGiven) - 使用此方法,我们可以安排在我们提供的时间延迟(以秒为单位)之后调用方法中给定的回调函数。
- new_event_loop() - 使用此方法,我们可以创建并返回一个新的事件循环项目。
- set_event_loop() - 借助此方法,我们可以将程序中当前执行上下文的事件循环设置为循环。
- run_forever() - 通过在程序中使用 loop.run_forever() 方法,我们可以运行循环,直到调用 stop() 方法为止。
现在,我们将查看一个 Python 程序示例,其中我们将使用事件循环方法,即 get_event_loop() 方法。通过使用此方法,我们将在事件中打印给定的命令。
示例:查看以下带有事件循环的 Python 程序:
# Importing asyncio module in the program
import asyncio
# A default function with event loops method
def loopText(loop):
# A text printing command
print('Printing this text through the event loop')
loop.stop() # Stopping the loop
loop = asyncio.get_event_loop() # Using get_event_loop() method to print the text
loop.call_soon(loopText, loop) # Using call_soon() method from event loops
loop.run_forever() # run_forever() on event loop
loop.close() # Closing the loop
输出
Printing this text through the event loop
解释:
我们首先在程序中导入了 asyncio 模块以使用事件循环方法。
然后,我们定义了一个默认函数,其中我们将 'loop' 作为参数,并在函数内部使用 print 命令。我们使用事件循环的 stop() 方法来停止事件。
然后,我们在程序中使用 get_event_loop() 方法获取默认函数中给定的文本。然后,在 call_soon() 事件循环方法中,我们使用函数名和函数参数作为参数。最后,我们使用 run_forever() 和 close() 事件循环方法。
Futures(未来对象)
在 asyncio 模块中提供的 Future 类与 concurrent.futures 方法兼容。asyncio 模块中的 Future 类代表尚未完成的程序计算。
并发的 Future 和 asyncio 的 Future 之间存在一些主要区别。
- 我们在 Future 类中使用 add_done_callback() 方法注册的回调函数只会通过事件循环中的 call_soon() 方法调用。
- Future 类中的 exception() 和 result() 方法不会接受超时或给定时间参数,当 Future 尚未完成这些函数时,它们会在输出中显示错误。
- 我们无法将 asyncio.futures.Future 类与 concurrent.futures 包中的 as_completed() 或 wait() 函数一起使用,因为它与它们不兼容。
现在,我们将查看以下 Python 程序示例,其中我们将使用 asyncio 模块的 Future 类方法并在输出中打印文本。
示例:
# Importing asyncio module in the program
import asyncio
# A default function from the async module using future parameter in it
async def myFunction(future):
await asyncio.sleep(2) # Using sleep() function of asyncio module
future.set_result('This text is printed using future class methods!') # Printing text from future parameter
# Using get_event_loop() method from event loop
loop = asyncio.get_event_loop()
future = asyncio.Future() # Using future() class method
# Calling default function from future class method
asyncio.ensure_future(myFunction(future))
# Using try & finally method future parameter of function
try:
loop.run_until_complete(future)
print(future.result()) # printing result from future class
finally:
loop.close() # finally closing the loop
输出
This text is printed using future class methods!
解释:
首先,在程序中导入 asyncio 模块和 time 模块以使用它们的函数。然后,我们使用 async 默认函数来设置要打印的已执行协程的任务。
我们使用 time 模块的 sleep() 函数在执行后的每个协程后休息 2 秒。
然后,我们使用另一个 async 默认函数来设置协程的循环。完成循环后,该函数将打印“任务已完成”的消息。最后,我们使用事件循环方法来运行和关闭程序中的循环。
协程
在 asyncio 模块中的协程概念与线程模块的线程对象中的协程概念非常相似。
asyncio 模块中的协程概念是子例程概念的一般化形式。
我们甚至可以在程序执行过程中挂起协程,以便挂起的协程将等待用户提供的外部处理。挂起的协程将在外部处理完全完成后返回到上次挂起的位置。
在 asyncio 模块协程中,我们可以通过以下两种方式来实现协程:
- @asyncio.coroutine 装饰器
- async def 函数()
让我们通过在 Python 程序中实现它们来了解这两种方法。
1. @asyncio.coroutine 装饰器
我们可以使用 asyncio 模块装饰器 @asyncio.coroutine 来利用生成器来实现程序中的协程。通过以下示例,我们可以理解带装饰器的协程的实现。
示例:查看以下 Python 程序:
# Importing asyncio module in the program
import asyncio
# Using @asyncio.coroutine decorator to implement coroutines
@asyncio.coroutine
# Using a default function with coroutine implementation
def operationCoroutine():
print("This text is present inside the coroutine of the asyncio module!") # Printing text inside coroutine
loop = asyncio.get_event_loop() # Using get_event_loop() method to print text
try:
loop.run_until_complete(operationCoroutine()) # Using run_until_complete() loop method on default function
finally:
loop.close() # closing the loop
输出
This text is present inside the coroutine of the asyncio module!
解释:
首先,在程序中导入 asyncio 模块后,我们使用装饰器 @asyncio.coroutine。然后,我们使用默认函数来使用协程方法来获取文本。接着,我们使用事件循环方法来在输出中打印文本。最后,我们使用 try 和 finish 方法来运行程序中的事件循环,并使用 close() 函数关闭循环。
2. async def 函数()
我们可以说,使用 async def 函数() 是实现协程的最通用方法,通过 asyncio 模块。通过以下示例,我们可以了解实现协程的这种方法。
示例:查看以下 Python 程序:
# Importing asyncio module in the program
import asyncio
# Using async def function() to implement coroutines
async def operationCoroutine():
print("This text is present inside the coroutine of the asyncio module!") # Printing text inside coroutine
loop = asyncio.get_event_loop() # Using get_event_loop() method to print text
try: loop.run_until_complete(operationCoroutine()) # Using run_until_complete() loop method on default function
finally:
loop.close() # closing the loop
输出
This text is present inside the coroutine of the asyncio module!
解释:
与实现协程的第一种方法相比,使用这种方法的实现协程的路径相同。在这种方法中,我们直接使用 asyncio 模块的 async def operationCoroutine() 函数来实现协程。
任务
任务是 asyncio 模块中的一个子类,负责在事件循环中以并行执行的方式执行 asyncio 协程。通过使用 Python 程序来执行协程的任务子类,我们可以了解任务子类的工作方式。
示例:
# Importing asyncio module in the program
import asyncio
# Importing time module
import time
# Using async default function()
async def Task_ex(n):
time.sleep(2) # sleep() function of time module
print("Loop event is processing coroutine no: {}".format(n)) # given printing tasks to print in output
# Generating tasks with async default function
async def Generator_task():
# looping over tasks using for loop
for i in range(10):
asyncio.ensure_future(Task_ex(i))
# After completing loop
print("All given tasks are completed")
asyncio.sleep(2)
loop = asyncio.get_event_loop() # printing in output using event loop method
loop.run_until_complete(Generator_task()) # Running the loop
loop.close() # Closing the loop
输出
Loop event is processing coroutine no: 0
Loop event is processing coroutine no: 1
Loop event is processing coroutine no: 2
Loop event is processing coroutine no: 3
Loop event is processing coroutine no: 4
Loop event is processing coroutine no: 5
Loop event is processing coroutine no: 6
Loop event is processing coroutine no: 7
Loop event is processing coroutine no: 8
Loop event is processing coroutine no: 9
All given tasks are completed
解释:
我们在程序中导入 asyncio 模块和 time 模块以使用其函数。然后,我们使用 async 默认函数来设置要打印的已执行协程的任务。
我们使用 time 模块的 sleep() 函数在执行后的每个协程后休息 2 秒。
然后,我们使用另一个 async 默认函数来设置协程的循环。完成循环后,该函数将打印“任务已完成”的消息。最后,我们使用事件循环方法来运行和关闭程序中的循环。
传输
传输是 asyncio 模块中提供给我们的类,我们可以使用它们在程序中实现各种类型的通信。传输类不是线程安全的,我们总是需要在通信通道建立后将它们与协议实例配对使用。
在 asyncio 传输类中,可以从基础传输类继承以下几种不同类型的传输:
- 数据报传输(Datagram transport):数据报传输是用于发送数据的接口。
- 读传输(Read Transport):读传输是只读模式的传输类接口。
- 写传输(Write Transport):这个传输是只写模式的传输类接口。
- 基本子进程传输(Base Subprocess Transport):基本子进程传输类的功能与基础传输类非常相似。
在上述提到的所有继承传输类中,仅从基础传输类中传递以下特定类型的方法:
- is_closing():如果指定的传输类已关闭或正在关闭,则此方法将返回 true。
- close():此方法用于关闭程序中正在运行的传输类。
- get_protocol():我们可以使用 get_protocol() 方法在返回中获取当前协议。
- get_extra_info(className, default=none):我们可以使用此方法获取有关在参数中给定的传输类的一些附加信息。
协议
在 asyncio 模块中,我们可以使用几个基类来在子类中实现网络协议。我们可以将这些类与传输类配对使用。协议将请求出站数据并解析入站数据,而传输类负责缓冲和实际的 I/O。
以下是三种协议类:
- 协议类(Protocol class):这是协议中的基类,我们可以使用它来实现用于与 SSL 和 TCP 传输一起使用的流式协议。
- 数据报协议类(Datagram protocol class):这是协议中的另一个基类,我们可以使用它来实现用于与 UDP 传输一起使用的数据报协议。
- 子进程协议类(Subprocess protocol class):我们可以使用此协议类的基类来实现使用一组单向管道与子进程进行通信的各种协议。