通过代码了解一下 Python 异步处理

通过代码了解了解 Python 异步处理

0. 背景

想了解一下 Python 的异步编程,所以就学习了一些示例代码。

1. 示例代码 1

controllers.py

import asyncio
from datetime import datetime


async def foo():
    print(f'{datetime.now()} Foo')


async def bar():
    while True:
        print(f'{datetime.now()} Bar')
        await asyncio.sleep(1)

代码说明,

这是一个使用 asyncio 库实现的 Python 异步编程示例。asyncio 是 Python 3.4 引入的标准库,用于编写协程(coroutine)和异步 I/O 代码。在这个示例中,定义了两个异步函数 foo 和 bar。

foo 函数是一个简单的异步函数,每次被调用时会打印当前时间和字符串 “Foo”。

bar 函数是一个无限循环的异步函数,每秒钟打印当前时间和字符串 “Bar”,然后等待 1 秒钟。这里使用了 asyncio.sleep() 函数来等待指定的时间。

在异步编程中,可以使用协程来实现非阻塞的异步操作。协程是一种轻量级的线程,可以在单个线程中运行多个协程,从而实现并发操作。在这个示例中,使用了 asyncio 库提供的协程机制来实现异步操作。使用 asyncio.run() 函数来运行这个示例,它会自动创建一个事件循环,并将 foo 和 bar 函数注册到事件循环中。

main.py

import asyncio
from controllers import foo, bar
from apscheduler.schedulers.asyncio import AsyncIOScheduler


async def main():
    # Init message
    print('\nPress Ctrl-C to quit at anytime!\n')

    scheduler = AsyncIOScheduler()
    scheduler.add_job(foo, "interval", seconds=2)
    scheduler.start()

    await asyncio.create_task(bar())


if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    loop.create_task(main())
    loop.run_forever()

代码说明,

这段代码使用了 asyncio 库和 apscheduler 库来实现一个定时任务调度器。具体来说,它定义了一个名为 main 的异步函数,它包含了以下步骤:

  1. 打印一条初始化消息,告诉用户如何退出程序。
  2. 创建一个 AsyncIOScheduler 对象,用于调度定时任务。
  3. 向调度器中添加一个名为 foo 的任务,每 2 秒钟运行一次。
  4. 启动调度器。
  5. 创建一个协程任务,调用名为 bar 的异步函数。
  6. 运行事件循环,等待协程任务完成。

如果运行的是这个文件,那么在最后一行的 if __name__ == "__main__" 分支中,会创建一个事件循环,并将 main 函数作为一个协程任务添加到事件循环中。然后,调用 loop.run_forever() 方法来运行事件循环,等待协程任务完成。这样,就可以实现定时任务调度器的功能。

运行效果,

Press Ctrl-C to quit at anytime!

2023-05-31 14:47:30.461780 Bar
2023-05-31 14:47:31.468809 Bar
2023-05-31 14:47:32.471349 Bar
2023-05-31 14:47:32.472350 Foo
2023-05-31 14:47:33.484869 Bar
2023-05-31 14:47:34.463051 Bar
2023-05-31 14:47:34.463051 Foo
2023-05-31 14:47:35.478448 Bar
2023-05-31 14:47:36.475942 Bar
2023-05-31 14:47:36.475942 Foo
2023-05-31 14:47:37.487639 Bar
2023-05-31 14:47:38.484124 Bar
...

2. 示例代码 2

basic_generation.py

import asyncio
import edge_tts
import pygame

# TEXT = "Hello World! Note that this code requires the requests and pygame modules to be installed. "
TEXT = "想了解一下 Python 的异步编程,所以就学习了一些示例代码。"
VOICE = "zh-CN-XiaoxiaoNeural"
OUTPUT_FILE = "./output/output.mp3"


async def _main() -> None:
    communicate = edge_tts.Communicate(TEXT, VOICE)
    await communicate.save(OUTPUT_FILE)
    pygame.mixer.init()
    pygame.mixer.music.load("./output/output.mp3")
    pygame.mixer.music.play()
    # Wait for audio to finish playing
    while pygame.mixer.music.get_busy():
        continue


if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    try:
        loop.run_until_complete(_main())
    finally:
        loop.close()

代码说明,

这段代码使用了 Python 的异步编程模块 asyncio 和 Edge TTS API,实现了将指定的文本转换为语音并播放的功能。具体来说,代码的主要功能如下:

  1. 导入必要的模块和变量,包括 asyncio、edge_tts 和 pygame。
  2. 定义要转换为语音的文本(TEXT)、所使用的语音合成引擎(VOICE)和输出文件路径3.(OUTPUT_FILE)。
  3. 定义一个异步函数 _main(),该函数使用 Edge TTS API 将文本转换为语音,并使用 pygame 播放输出的音频文件。
  4. 在主函数中,获取异步事件循环,并运行 _main() 函数直到完成。
  5. 最后,关闭异步事件循环。

具体实现过程如下:

  1. 使用 edge_tts.Communicate() 函数创建一个 Communicate 对象,该对象包含了要转换为语音的文本和所使用的语音合成引擎。
  2. 使用 await communicate.save(OUTPUT_FILE) 异步保存输出的音频文件到指定路径。
  3. 初始化 pygame 模块,使用 pygame.mixer.music.load() 函数加载输出的音频文件。
  4. 使用 pygame.mixer.music.play() 函数播放加载的音频文件。
  5. 在 while 循环中,使用 pygame.mixer.music.get_busy() 函数检查音频是否正在播放,如果正在播放则继续循环,直到音频播放完成为止。

3. 示例代码 3

main.py

import asyncio
import threading


async def my_coroutine():
    print("Start coroutine...")
    await asyncio.sleep(3)
    print("Coroutine finished.")


def run_in_thread(loop):
    asyncio.set_event_loop(loop)
    loop.run_until_complete(my_coroutine())


if __name__ == "__main__":
    loop = asyncio.new_event_loop()
    t = threading.Thread(target=run_in_thread, args=(loop,))
    t.start()
    t.join()
    loop.close()

代码说明,

这个示例代码创建了一个协程 my_coroutine(),它会在开始时打印一条消息,然后等待 3 秒钟,最后再打印一条消息。

接着,我们定义了一个名为 run_in_thread() 的函数,它接受一个事件循环对象 loop 作为参数,然后将这个事件循环对象设置为当前线程的默认事件循环,并运行协程 my_coroutine()。

在主程序中,我们首先创建了一个新的事件循环对象 loop,然后创建了一个新的线程 t,并将 run_in_thread() 函数作为它的目标函数。我们将事件循环对象 loop 作为参数传递给 run_in_thread() 函数,以便让它在新线程中运行协程 my_coroutine()。

最后,我们启动线程 t,等待它完成,然后关闭事件循环对象 loop。这样,我们就实现了在一个新线程中运行协程的功能。

在 Python 中,t.join() 是一个线程方法,它的作用是等待当前线程(即调用方法的线程)执行完毕。

在上面的示例代码中,我们创建了一个名为 t 的新线程,并在其中运行了协程 my_coroutine()。接着,我们调用 t.join() 方法,这会使主线程等待 t 线程执行完毕,然后再继续执行下面的代码。

如果我们不调用 t.join() 方法,那么主线程就会立即继续执行下面的代码,而不会等待 t 线程执行完毕。这可能会导致程序出现一些意外的行为,因为 t 线程可能还没有完成它的任务,而主线程已经开始执行下面的代码了。

因此,调用 t.join() 方法可以确保在主线程继续执行下面的代码之前,t 线程已经完成了它的任务。

未完待续!

猜你喜欢

转载自blog.csdn.net/engchina/article/details/130968863