[英]Python - Using the return variable of an awaited function Asyncio
[英]Python asyncio skip processing untill function return
我仍然對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庫是同步的,但我想這是另一天的問題......
評論包含您響應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像:
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
一起使用,並且應該與其他異步函數一起使用。
對於生成大型PDF的任務,您可以使用異步任務/作業隊列。 例如,您可以使用Celery 。 由於您不想等待任務,而是返回一個回復,例如“生成PDF,請等待一分鍾/秒”。 因此,當請求到達“生成PDF”端點時,您將在Celery中創建一個任務,Celery將異步處理它,完成后,您可以推送到客戶端或客戶端可以使用任務ID來使用“任務查找”(或者當你實施)。 以下是一個示例答案 - 如何在Celery中檢查任務狀態?
Celery和Asyncio之間的區別在於,Celery可以在完全獨立的環境中執行任務,並且與服務器的通信是通過像RabbitMQ這樣的分布式消息傳遞完成的。 Asyncio使用協同程序來利用阻塞I / O時間。 它將使用服務器所在的相同環境和處理器。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.