我仍然对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库是同步的,但是我想这又是一个问题...
答案 0 :(得分: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
。这样,即使数据库或图像服务器运行缓慢,请求也不会被阻止。一切都在同一个异步线程中运行。
如果其中一些尚未异步,则可以将它们与run_in_executor
一起使用,并且应该可以与其他异步功能配合使用。
答案 1 :(得分:1)
答案 2 :(得分:0)
对于您的任务,生成大型PDF,可以使用异步任务/作业队列。例如,您可以使用Celery。由于您不想等待任务,因此请返回诸如“生成PDF,请等待一分钟/秒”之类的答复。因此,当请求到达“生成PDF”端点时,您将在Celery中创建一个任务,而Celery将异步处理该任务,完成后,您可以推送到客户端,或者客户端可以使用task-id使用“任务查找”(或实施时)。这是一个示例答案-How to check task status in Celery?
Celery和Asyncio之间的区别在于,Celery可以在完全独立的环境中执行任务,并且与服务器的通信是通过像RabbitMQ这样的分布式消息来完成的。 Asyncio使用协程来利用阻塞I / O时间的地方。它将使用服务器所在的环境和处理器。