Python事件驱动编程
在本教程中,我们将学习事件驱动编程以及可以用来进行Python事件驱动编程的Python模块(Asyncio)。
事件驱动编程
最终,程序的流程取决于事件,而专注于事件的编程称为事件驱动编程。我们之前只涉及到并行或顺序模型,但现在我们将讨论异步模型。遵循事件驱动编程概念的编程模型称为异步模型。事件驱动编程的工作取决于程序中发生的事件。
除此之外,它还取决于程序事件循环,它始终监听程序中的新事件。一旦程序中启动了事件循环,那么只有事件才会决定执行内容以及执行顺序。
请查看下面的事件循环流程图,以了解事件驱动编程中事件的工作原理:
Asyncio- Python事件驱动编程模块
Asyncio模块在Python 3.4版本中被添加,并且在以后的Python版本中都可用。Asyncio模块提供了一个非常好的基础设施,可以使用程序中的协程来编写单线程的并发代码。
在Python的Asyncio模块中,进行事件驱动编程时使用了以下不同的概念:
- 事件循环
- Future
- 协程(Coroutines)
- @asyncio.coroutine装饰器
- 任务(Tasks)
- 传输(Transports)
- 和协议(Protocols)
让我们详细了解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’作为参数,并在函数内部使用了打印命令。我们使用了事件循环的stop()方法来停止事件。
之后,我们在循环参数上使用了get_event_loop()方法来打印默认函数中的文本。然后,在call_soon()事件循环方法中,我们使用了函数名和函数的参数作为参数。最后,我们使用了run_forever()和close()事件循环方法。
Futures
在asyncio模块中提供的Future类与concurrent.futures方法兼容。asyncio模块中给出的future类表示程序中尚未完成的计算。
concurrent.futures.Future和asyncio.futures之间有一些重要的区别。
- 使用add_done_callback()方法在future类中注册的回调函数将始终通过事件循环中的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!
解释:
我们首先定义了一个默认函数,即’myFunction’,参数是future。在函数内部,我们使用sleep()方法来执行两秒的暂停。
然后,我们使用future类的方法来给出要打印在结果中的文本。我们从程序中的事件循环中使用get_event_loop方法。然后,我们在默认函数中给出的future参数上使用future()类方法。
现在,我们可以在输出中打印文本,因为我们在其中使用了future。为了打印输出中的文本,我们使用try和finish方法,其中在try方法中,我们调用了打印命令,在finish方法中,我们使用close()方法关闭了循环。
协程
asyncio模块中的协程概念与线程模块中的协程概念非常相似。
asyncio模块中协程的概念是子例程概念的推广形式。
我们甚至可以在程序执行期间暂停协程,以便暂停的协程将等待用户提供的外部处理。只有在外部处理完全完成后,暂停的协程才会返回到上次暂停的位置。
在asyncio模块的协程中,我们可以使用以下两种方法来帮助我们在程序中实现协程:
- @asyncio.coroutine装饰器
- async def function()
通过在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装饰器。然后,我们使用默认函数来使用协程方法获取文本。之后,我们使用事件循环的get_event_loop()方法在输出中打印文本。最后,我们在默认函数上使用了’try和finally’方法,并使用close()函数关闭了程序中的循环。
2. async def function()
我们可以说async def function()是使用asyncio模块实现协程的最通用方法。我们可以通过以下示例来理解通过def function()实现协程的方法。
示例: 看以下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
Explanation:
我们在程序中导入了asyncio和time模块来使用它们的函数。然后,我们使用了一个异步的默认函数来设置打印已处理协程的任务。
我们使用time模块的sleep()函数,在每个执行的协程后休息2秒钟。
然后,我们使用另一个异步的默认函数来设置在其中循环任务。完成循环后,该函数将打印“任务完成”。最后,我们使用事件循环方法来运行和关闭程序中的循环。
运输类
运输类是在asyncio模块中提供给我们的类,我们可以使用它们来实现程序中各种类型的通信。运输类不是线程安全的,我们始终必须在建立通信渠道后将它们与协议实例配对使用。
在asyncio运输类中,可以从基础运输类继承以下类型的运输类:
- 数据报运输 :数据报运输是我们用于发送数据的接口。
- 读运输: 读运输是仅具有只读模式的运输类的接口。
- 写运输: 写运输是仅具有只写模式的继承运输类的接口。
- 基本子进程运输: 基本子进程运输类的功能与基本运输类非常相似。
在上述所有继承的运输类中,仅随后从基础运输类传递以下不同类型的方法:
- is_closing(): 该方法仅在给定的传输类已关闭或正在关闭时返回true。
- close(): 该方法用于关闭程序中正在运行的当前传输类。
- get_protocol(): 我们可以使用传输类中的get_protocol()方法来返回当前协议。
- get_extra_info(className, default = none ):我们可以使用此方法来获取关于传递的传输类的一些附加信息。
协议
在asyncio模块中,我们提供了几个基础类,我们可以使用它们来在子类中实现网络协议。我们可以将这些类与运输类一起使用。协议将要求发送数据并解析接收到的数据,而传输类负责缓冲和实际的I/O。
以下是协议的三个类:
- 协议类 :它是协议中的基类,我们可以用它来实现与SSL和TCP传输一起使用的流协议。
- 数据报协议类: 它是协议中的另一个基类,我们可以用它来实现与UDP传输一起使用的数据报协议。
- 子进程协议类: 我们可以使用此协议中的基类来实现使用一组单向管道与子进程进行通信的各种协议。