7

私はまだ asyncio の仕組みについて非常に混乱しているので、簡単な例を設定しようとしましたが、それを達成できませんでした。

次の例は、大きな PDF を生成する要求を受信する Web サーバー (Quart) です。サーバーは、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ライブラリは同期していますが、それは別の日の問題だと思います...

4

3 に答える 3

7

コメントには、Web リクエストに応答し、後で PDF 生成をスケジュールするために必要なすべてが含まれています。

asyncio.create_task(generatePdf())

ただし、asyncio イベント スレッドをブロックするため、pdf 処理が遅い場合はお勧めできません。つまり、現在のリクエストはすぐに応答されますが、次のリクエストは PDF 生成が完了するまで待たなければなりません。

正しい方法は、executor (特に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。これにより、データベースや画像サーバーの速度が遅くても、リクエストがブロックされることはありません。すべてが同じ asyncio スレッドで実行されます。

それらのいくつかがまだ非同期である場合、それらはrun_in_executor他の非同期関数と一緒に使用でき、うまく機能するはずです。

于 2019-01-28T16:02:31.073 に答える