如何使函数异步运行?

2024-10-01 05:01:29 发布

您现在位置:Python中文网/ 问答频道 /正文

我最近在Python中运行异步函数,我想知道如何将同步函数转换为异步函数

例如,有一个通过谷歌api进行翻译的库。人们很可能想知道,如何异步翻译许多不同的单词。当然,你可以把它放在一个请求中,但是谷歌API会认为它是一个文本并相应地处理它,这将导致不正确的结果。

你怎么能把这个密码翻过来:

from pygoogletranslation import Translator
translator = Translator()
translations = []
words = ['partying', 'sightseeing', 'sleeping', 'catering']
for word in words:
    translations.append(translator.translate(word, src='en', dest='es'))
print(translations)

为此:

from pygoogletranslation import Translator
import asyncio
translator = Translator()
translation_tasks = []
words = ['partying', 'sightseeing', 'sleeping', 'catering']
for word in words:
    asyncio.create_task(translator.translate(word, src='en', dest='es'))
translations = asyncio.run(
    asyncio.gather(translation_tasks, return_exceptions=True) 
)
print(translations)

考虑到函数translate没有内置的async实现


Tags: 函数fromimportasynciotranslatewordwordstranslator
3条回答

正如在其他答案中提到的,调用阻塞函数对于ayncio是无用的。在这种情况下,我建议您使用^{},这是谷歌的官方翻译库

您可以在当前库中执行类似操作:

async def do_task(word):
    return translator.translate(word, ...)

def main():
    # Create translator
    ...
    asyncio.gather(do_task(word) for word in [])

但这将以相同的方式运行任务,而不使用asyncio。asyncio的真正好处是,当某个东西挂起或等待时,它可以做其他事情。例如,在等待服务器的响应时,它可以发送另一个请求

Python如何知道某些工作正在等待完成?仅当函数(此处为coroutine)通过await关键字通知事件循环时。因此,您肯定需要使用本机支持异步操作的库。上面提到的google-cloud-translate就是这样一个库。你可以做:

from google.cloud import translate


async def main():
    # Async-supported google translator client
    client = translate.TranslationServiceAsyncClient()
    words = ['partying', 'sightseeing', 'sleeping', 'catering']
    results = await asyncio.gather(*[client.translate_text(parent=f"projects/{project_name}", contents=[word], source_language_code="en", target_language_code="es") for word in words])
    print(results)

asyncio.run(main())

您可以看到,这个客户机实际上将字符串列表作为输入,因此您可以直接在这里传递字符串列表。根据docs,这一限制是1024。所以,如果你的列表更大,你必须使用这个for循环

但是,您可能必须为此客户端设置凭据等,这超出了此问题的范围

您必须创建一个async函数,然后运行它。虽然如果translate没有内置的async支持或正在阻塞,但是使用async不会使它更快。按照注释中的建议,使用多线程/多处理可能更好

async def main():
    async def one_iteration(word):
        output.append(translator.translate(word, src='en', dest='es'))
    coros = [one_iteration(word) for word in words]
    await asyncio.gather(*coros)
asyncio.run(main())

要使函数异步,您需要使用async def来定义它,并将其更改为对任何可能阻塞的对象使用其他异步函数-例如,您将使用aiohttp而不是requests,等等。这项工作的重点是,该函数随后可以由事件循环与其他此类函数一起执行。每当异步函数需要等待某件事情时,如await关键字所示,它将挂起到事件循环,并给其他函数一个执行的机会。事件循环将无缝地协调可能大量此类异步函数的并发执行。有关更多详细信息,请参见例如this answer

如果您所依赖的关键阻塞函数没有异步实现,则可以使用^{}(或者,从Python 3.9开始,^{})使其异步。但是,请注意,这些解决方案是“欺骗”的,因为它们在引擎盖下使用线程,因此它们不会提供通常由asyncio关联的好处,例如扩展到线程池中的线程数之外的能力,或者取消执行协程的能力

相关问题 更多 >