您的位置:

Python 事件驱动编程

在本教程中,我们将学习事件驱动编程以及可以用来进行 Python 事件驱动编程的 Python 模块(Asyncio)。

事件驱动编程

最终,程序的流程依赖于事件,而专注于事件的编程称为事件驱动编程。我们只处理并行或顺序模型,但是现在我们将讨论异步模型。遵循事件驱动编程概念的编程模型称为异步模型。事件驱动编程的工作依赖于程序中发生的事件。

除此之外,它还依赖于程序的事件循环,该循环总是在程序中监听新的传入事件。一旦一个事件循环在程序中开始,那么只有事件将决定执行什么和以什么顺序执行。

查看下面的事件循环流程图,了解事件驱动编程中事件的工作方式:

事件驱动pexpect模块

asyncio模块是在 3.4 版本中添加到 Python 中的,它在 Python 的所有更高版本中都可用。Asyncio 模块为使用程序中的 coroutines 将并发代码编写为单线程提供了非常好的基础设施。

在 Python 的 asyncio模块中,在进行事件驱动编程时使用了以下不同的概念:

  • 事件循环
  • 期货
  • 协程
  • @asyncio .装饰程式
  • 任务
  • 运输
  • 和协议

让我们详细了解 asyncio模块使用的所有这些不同的概念,并了解它们在进行事件驱动编程时是如何工作的。

事件循环

事件循环是 asyncio模块的一项功能,用于处理计算程序中发生的所有事件。当整个程序正在执行时,事件循环的行为就像是在绕路,它还会跟踪已执行的事件和新的传入事件。asyncio模块的一个主要优点是,每个进程只允许一个事件循环。

asyncio模块中,我们有一些方法可以用来管理代码中的事件循环。asyncio模块中提供了以下方法。

  • time() - 我们可以根据事件循环中存在的内部时钟,用这个方法将当前时间返回给用户。
  • loop = get_event_loop() - 通过使用这个方法,我们将根据程序中执行的当前上下文得到事件循环作为回报。
  • call_soon(CallbackFunction,ArgumentGiven) - 有了这个函数,我们可以安排一个回调函数尽快被调用。当控件返回到事件循环并且 call_soon()返回后,参数中给出的回调函数将被调用。
  • call late(time to _ delived,CallbackFunction,ArgumentGiven) - 使用这个方法,我们可以安排在我们提供的时间延迟(以秒为单位)之后调用方法中给出的回调函数。
  • new_event_loop() - 使用这个方法,我们可以创建并返回一个新的事件 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()事件循环方法。

期货

asyncio模块中给出的未来类与 concurrent.futures 方法兼容。asyncio模块中给出的未来类代表程序中的计算,这还没有完成。

期货和期货之间有一些主要的区别

  • 我们在将来的类中用 add_done_callback()方法注册的回调函数将始终只通过事件循环中的 call_soon()方法来调用。
  • future 类中的 exception()和 result()方法不会接受超时或给定时间的参数,当这些函数的 future 尚未完成时,它们会在输出中显示一个错误。
  • 我们不能将 asyncio.futures.Future 类与 concurrent.futures 包中的 as_completed()或 wait()函数一起使用,因为它与它们不兼容。

现在,我们将在下面的示例中查看一个 Python 程序,其中我们将使用 asyncio模块中的未来类方法,并在输出中打印文本。

示例:


# 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()方法作为执行的两秒暂停。

然后,我们使用未来的类方法给出了我们想要打印在结果中的文本。我们在程序中使用了事件循环中的 get_event_loop 方法。然后,我们对默认函数中给出的 future 参数使用了 future()类方法。

现在,我们可以在输出中打印文本,就像我们在其中使用了未来一样。为了打印输出中的文本,我们使用了 try 和 finish 方法,其中 try 方法调用了 printing 命令,finish 方法使用 close()方法关闭了循环。

协程

asyncio模块内部的协同概念非常类似于线程模块线程对象中的协同概念。

asyncio模块中的协同概念是子程序概念的推广形式。

我们甚至可以在程序执行期间挂起一个协程,这样挂起的协程将等待用户给出的外部处理。只有在外部处理完成后,暂停的协程才会返回到上次暂停的位置。

asyncio模块协程中,我们可以使用以下两种方式来帮助我们在程序中实现协程:

  1. @asyncio .装饰程式
  2. 异步定义函数()

让我们通过在 Python 程序中使用它们的实现来理解这两种方式。

1 .@asyncio .装饰例程〔t1〕

我们可以利用带有 asyncio模块装饰器的生成器,即@asyncio.coroutine 装饰器,在程序内部实现协程。我们可以通过下面的例子理解协程和 decorator 的实现。

示例:看看下面的 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 and finally”方法,并使用 close()函数关闭了程序中的循环。

2。异步定义函数()

我们可以说 async def 函数()是 asyncio模块实现协程的最通用的方法。我们可以通过下面的例子理解这个用 def 函数()实现 coroutines 的方法。

示例:看看下面的 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!

说明:

像第一种实现协程的方法一样,我们在这个方法中也遵循了同样的路径。在这个方法中,我们没有使用装饰器,然后为 coroutines 定义默认函数,而是直接使用 asyncio模块的 async def operationCoroutine()函数来实现 coroutines。

任务

Tasks 是 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 和时间模块来使用它的功能。然后,我们使用异步默认函数来设置打印已处理的协程的任务。

我们使用时间模块的 sleep()函数,在打印每个执行的协程后,给出 2 秒的休息时间。

然后,我们使用另一个异步默认函数来设置其中任务的循环。完成循环后,该功能将打印“任务已完成”最后,我们使用事件循环方法来运行和关闭程序中的循环。

运输

Transports 是 asyncio模块中提供给我们的类,我们可以使用它们在程序中实现各种类型的通信。传输类不是线程安全的,我们总是必须在通信通道建立后将它们与协议实例配对。

在 asyncio 传输类中,程序中可以从基本传输类继承以下类型的传输:

  1. 数据报传输:数据报传输是我们用来发送数据的接口。
  2. 读传输:读传输是只读模式传输类的接口。
  3. 写传输:这个传输是继承的传输类的接口,只有只写模式。
  4. 基本子流程传输:基本子流程传输类的功能与基本传输类非常相似。

在所有上述继承的传输类中,只有以下不同类型的方法随后从基本传输类中过渡出来:

  1. is_closing(): 只有当参数中给定的传输类已经关闭并且正在关闭时,此方法才会返回 true。
  2. close(): 此方法用于关闭程序中正在运行的当前传输类。
  3. get_protocol(): 我们可以使用 transport 类中的 get_protocol()方法来获取当前协议作为回报。
  4. get_extra_info(className,default = none ):我们可以使用这个方法获取一些关于我们在参数中给出的传输类的附加信息。

协议

asyncio模块中,我们提供了几个基类,可以用它们在子类中实现我们的网络协议。我们可以将这样的类与传输类结合使用。该协议将请求输出数据并解析输入数据,而传输类负责缓冲和实际输入/输出

以下是三类协议:

  1. 协议类:它是协议中的基类,我们可以用它来实现与 SSL 和 TCP 传输一起使用的流协议。
  2. 数据报协议类:它是协议中的另一个基类,我们可以用来实现与 UDP 传输一起使用的数据报协议。
  3. 子进程协议类:我们可以使用协议中的这个基类来实现使用一组单向管道来传递子进程的各种协议。