Python asyncio 跳过处理直到函数返回

标签 python python-asyncio python-3.7 quart asgi

我对 asyncio 的工作原理仍然很困惑,所以我试图设置一个简单的示例但无法实现。

以下示例是一个 Web 服务器 (Quart),它接收到生成大型 PDF 的请求,然后服务器在开始处理 PDF 之前返回一个响应,然后开始处理它,稍后将下载链接发送到电子邮件中。

from quart import Quart
import asyncio
import time

app = Quart(__name__)

@app.route('/')
async def pdf():
    t1 = time.time()
    await generatePdf()
    return 'Time to execute : {} seconds'.format(time.time() - t1)

async def generatePdf():
    await asyncio.sleep(5)
    #sync generatepdf
    #send pdf link to email

app.run()

我该怎么做?在上面的示例中,我不希望在返回之前等待 5 秒。

我什至不确定 asyncio 是否是我需要的。

而且我担心在响应返回后阻止服务器应用程序不是应该做的事情,但也不确定。

pdf 库也是同步的,但我想这是另一天的问题......

最佳答案

评论包含您响应网络请求和安排稍后生成 pdf 所需的一切。

asyncio.create_task(generatePdf())

但是,如果 pdf 处理缓慢,则不是一个好主意,因为它会阻塞异步事件线程。即当前请求将得到快速响应,但后续请求必须等到 pdf 生成完成。

正确的方法是在执行器中运行任务(尤其是 ProcessPoolExecutor )。

from quart import Quart
import asyncio
import time
from concurrent.futures import ProcessPoolExecutor

app = Quart(__name__)
executor = ProcessPoolExecutor(max_workers=5)

@app.route('/')
async def pdf():
    t1 = time.time()
    asyncio.get_running_loop().run_in_executor(executor, generatePdf)
    # await generatePdf()
    return 'Time to execute : {} seconds'.format(time.time() - t1)

def generatePdf():
    #sync generatepdf
    #send pdf link to email

app.run()

重要的是要注意,因为它在不同的进程中运行,generatePdf 不能在没有同步的情况下访问任何数据。所以在调用函数时传递函数需要的一切。


更新

如果您可以重构 generatePdf 函数并使其异步,则效果最佳。

生成 pdf 的例子

def generatePdf():
    image1 = downloadImage(image1Url)
    image2 = downloadImage(image2Url)
    data = queryData()
    pdfFile = makePdf(image1, image2, data)
    link = upLoadToS3(pdfFile)
    sendEmail(link)

您可以像这样使函数异步:

async def generatePdf():
    image1, image2, data = await asyncio.gather(downloadImage(image1Url), downloadImage(image2Url), queryData())
    pdfFile = makePdf(image1, image2, data)
    link = await upLoadToS3(pdfFile)
    await sendEmail(link) 

注意:所有辅助函数,如downloadImagequeryData 都需要重写以支持async。这样,即使数据库或图像服务器很慢,请求也不会被阻止。一切都在同一个异步线程中运行。

如果它们中的一些还不是异步的,那么它们可以与 run_in_executor 一起使用,并且应该可以很好地与其他异步函数一起使用。

关于Python asyncio 跳过处理直到函数返回,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54370505/

相关文章:

Python:如何打印范围 a-z?

cookies - Cookie 错误 : Illegal Key

python - 如何在不 sleep 的情况下对该协程进行单元测试

python - 两行 Python 代码导致 3 个执行 block

python - 将行高应用于第 7 行及其之后的所有行

python - Python 中非本地语句的语法错误

python - 如何使用 Bokeh 在绘图上显示各种悬停标识符?

python - asyncio的事件循环使用什么调度算法?

pyspark - 当变量被动态分配时,mypy 类型检查显示错误

python - 有没有办法从 ElementTree 元素中获取行号