簡體   English   中英

在 Python RQ 中執行等待/異步 function

[英]Executing an awaitable / async function in Python RQ

我的工作都是需要按照 object 提出的一系列請求。 即,它的User有幾個數據點(可能有數百個),需要通過請求添加到該用戶。 我最初編寫了這些請求以同步運行,但它阻塞且緩慢。 我將每個User作業發送到 Python RQ 並有 10 名工作人員通過將用戶發送到隊列中。 1 個工作人員,1 個用戶,阻塞請求。

我已經重新編寫了我的用戶作業以使用 aiohttp 而不是 python 請求,並且速度明顯更快。 在 Python RQ 文檔中,它說“任何 Python function 調用都可以放在 RQ 隊列中。” 但我不知道如何將我的異步 function 發送到隊列中?


async def get_prices(calls: List[dict]) -> List[dict]:
     async with aiohttp.ClientSession() as session:
         for price in prices.items():
                price_type, date = price
                price = await pg.get_price(
                    session=session, lookup_date=date
                )
        do_some_other_stuff()
        await session.close()


from core.extensions import test_queue
from prices import get_prices
job = test_queue.enqueue(get_prices, kwargs={"username":'username'})

問題是永遠不會等待get_prices ,它只是一個協程期貨......我如何在隊列中等待我的 function?

由於python-rq不會直接支持 asyncio,因此您可以使用調用asyncio.run的同步 function 來代替。

async def _get_prices(calls: List[dict]) -> List[dict]:
    # ...

def get_prices(*args, **kwargs):
    asyncio.run(_get_prices(*args, **kwargs))

但是請注意, asyncio.run僅在沒有其他正在運行的事件循環時才有效。 如果您希望 asyncio 循環已經在運行,請改用loop.create_task

def get_prices(*args, **kwargs):
    loop = asyncio.get_event_loop()
    coro = _get_prices(*args, **kwargs)
    loop.create_task(coro)

然后當python-rq調用get_prices時,它會導致異步 function 被執行。

另一種選擇是不使用 asyncio 來發出請求,例如使用grequests 、線程或類似的東西,它可以與同步函數一起使用。

您可以考慮使用arq

由 Pydantic 的維護者創建,它不是一回事,而是受到 rq 的啟發。

此外,它仍然是 Redis 和隊列(現在使用asyncio )。

文檔

python 中的作業隊列和 RPC,帶有 asyncio 和 redis。

arq 被認為是 rq 的簡單、現代和高性能的繼任者。

簡單用法:

import asyncio
from aiohttp import ClientSession
from arq import create_pool
from arq.connections import RedisSettings

async def download_content(ctx, url):
    session: ClientSession = ctx['session']
    async with session.get(url) as response:
        content = await response.text()
        print(f'{url}: {content:.80}...')
    return len(content)

async def startup(ctx):
    ctx['session'] = ClientSession()

async def shutdown(ctx):
    await ctx['session'].close()

async def main():
    redis = await create_pool(RedisSettings())
    for url in ('https://facebook.com', 'https://microsoft.com', 'https://github.com'):
        await redis.enqueue_job('download_content', url)

# WorkerSettings defines the settings to use when creating the work,
# it's used by the arq cli.
# For a list of available settings, see https://arq-docs.helpmanual.io/#arq.worker.Worker
class WorkerSettings:
    functions = [download_content]
    on_startup = startup
    on_shutdown = shutdown

if __name__ == '__main__':
    asyncio.run(main())

暫無
暫無

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

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