簡體   English   中英

Python 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) 

注意:需要重寫所有幫助函數,如downloadImagequeryData以支持async 這樣,即使數據庫或映像服務器速度很慢,也不會阻止請求。 一切都在同一個asyncio線程中運行。

如果其中一些還沒有異步,那些可以與run_in_executor一起使用,並且應該與其他異步函數一起使用。

  1. 我強烈建議我閱讀Brad Solomon關於並行編程和python中的asyncio的這篇解釋性文章
  2. 對於異步執行任務,而不需要阻止請求,直到任務完成的目的-我認為最好的辦法是使用一個隊列 ,與從隊列模式消耗“的pdfGenerator”級(也涵蓋在文章)

對於生成大型PDF的任務,您可以使用異步任務/作業隊列。 例如,您可以使用Celery 由於您不想等待任務,而是返回一個回復,例如“生成PDF,請等待一分鍾/秒”。 因此,當請求到達“生成PDF”端點時,您將在Celery中創建一個任務,Celery將異步處理它,完成后,您可以推送到客戶端或客戶端可以使用任務ID來使用“任務查找”(或者當你實施)。 以下是一個示例答案 - 如何在Celery中檢查任務狀態?

Celery和Asyncio之間的區別在於,Celery可以在完全獨立的環境中執行任務,並且與服務器的通信是通過像RabbitMQ這樣的分布式消息傳遞完成的。 Asyncio使用協同程序來利用阻塞I / O時間。 它將使用服務器所在的相同環境和處理器。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM