![](/img/trans.png)
[英]How to write your own async/awaitable coroutine function in Python?
[英]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.