Python的ASYNCIO跳过处理,直到函数返回

问题描述 投票:6回答:3

我还是如何ASYNCIO作品很迷茫,所以我想设置一个简单的例子,但未能实现。

下面的例子是接收产生大量PDF的请求的Web服务器(夸脱),然后服务器会返回处理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库是同步的,但我想这是另一天的问题...

python python-asyncio python-3.7 quart asgi
3个回答
6
投票

注释有你需要的响应web请求,并安排PDF生成供以后的一切。

asyncio.create_task(generatePdf())

但是它不是如果PDF处理速度很慢,因为它会阻止ASYNCIO事件线程是一个好主意。即当前的请求将被迅速作出反应,但下面的请求将不得不等待,直到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) 

注:所有喜欢downloadImage的辅助功能,queryData需要重写以支持async。通过这种方式,请求将得不到即使数据库或图像服务器慢阻塞。一切都在同一ASYNCIO线程中运行。

如果他们中的一些尚未异步,那些可以用run_in_executor使用,并应工作好与其他异步功能。


1
投票
  1. 我强烈建议在阅读本explanatory article由布拉德·所罗门在并行编程和蟒蛇ASYNCIO。
  2. 对于异步执行任务,而不需要阻止请求,直到任务完成的目的 - 我认为最好的办法是使用queue与从队列模式消耗“的pdfGenerator”级(也是在covered文章)

0
投票

对于你的任务,产生较大的PDF,你可以使用一个异步任务/作业队列。举个例子,你可以使用Celery。既然你不想等待任务,而返回希望得到答复 - “生成PDF,请等待一分钟/秒”。所以,当一个请求到达“生成PDF”端点,您将芹菜中创建一个任务,芹菜会异步处理,并完成后,你可以推到客户端或客户端可以使用“任务查找”使用任务ID(或者当你实现)。下面是一个例子答案 - How to check task status in Celery?

芹菜和ASYNCIO之间的区别是,芹菜可在完全分离的环境中执行一个任务,并与服务器的通信是通过使像RabbitMQ一个分布式消息来完成。凡ASYNCIO使用协同程序利用阻塞I / O时间。它会使用相同的环境和你服务器所在的处理器。

© www.soinside.com 2019 - 2024. All rights reserved.