[英]Passing *args and **kwargs to an asyncio periodic wrapper function from a dictionary
我正在使用asyncio從字典中收集任務並執行它們,但是我很難使其按預期工作。 (這是我在此處提出的問題的后續問題,但是我重新編寫了一下代碼,因為它沒有按預期工作,並決定最好使用包裝器函數。)
因此,我使用包裝器來調用指定的任務函數。 我希望包裝程序將任何* args或** kwargs轉發到任務函數,並且如果設置了interval
kwarg,還希望定期重復執行該任務。
我如何將這些信息傳遞給包裝器和任務功能,同時又易於將新任務添加到tasks
字典中,從而使其易於維護?
請看一下我的代碼以作說明。
import asyncio
import random
async def run_task(taskname, taskfunc, interval=None, *args, **kwargs):
# Wrapper which will run the specified function, and repeat it if 'interval' is set.
# Should also be able to pass any potential *args and **kwargs to the function.
fakedelay = random.randint(1,6)
print(f'{taskname} started (completing in {fakedelay} seconds)')
await taskfunc(fakedelay, *args, **kwargs)
print(f'{taskname} completed after {fakedelay} seconds')
if interval is not None:
print(f'Repeating {taskname} in {interval} seconds...')
while True:
await taskfunc(fakedelay, *args, **kwargs)
await asyncio.sleep(interval)
async def faketask(fakedelay, *args, **kwargs):
# Function to simulate a coroutine task
await asyncio.sleep(fakedelay)
async def main():
tasks = {
# Dictionary of tasks to perform
'Task-1': faketask,
'Task-2': faketask,
'Task-3': faketask,
}
tasklist = []
for taskname, taskfunc in tasks.items():
tasklist.append(run_task(taskname, taskfunc))
print(f'Added {taskname} to job queue.')
await asyncio.gather(*tasklist)
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()
到目前為止,這似乎運作良好。 但是,假設我希望Task-3 在每次完成后每10秒重復一次。 我想簡單地在tasks
字典中指定它,以使其在將來添加新任務時盡可能地簡單。 例如:
tasks = {
# Dictionary of tasks to perform
'Task-1': faketask,
'Task-2': faketask,
'Task-3': faketask(interval=10),
}
但是運行該命令會TypeError: faketask() missing 1 required positional argument: 'fakedelay'
我認為這是有道理的,因為interval
kwarg是用於包裝程序的,而不是任務函數( faketask
)本身的。 而且包裝器似乎無法添加任何* args或** kwargs(在這種情況下為fakedelay
)。
在上一個問題中,我被建議使用functools.partial
。
tasks = {
'Task-1': faketask,
'Task-2': faketask,
'Task-3': functools.partial(faketask, interval=10),
}
它在某種程度上解決了我上一個問題的問題,但是在重新編寫代碼並添加了包裝函數之后,它現在似乎什么也沒做,並且坦白地講,我在理解functools.partial
是如何使用方面有困難。
所以我的問題是
我該怎么做,這是完成我要嘗試的工作的適當方法嗎?
我如何以盡可能簡單的方式(在新任務可以輕松添加的情況下)為tasks
字典中的特定函數提供* args和** kwarg,並通過包裝將它們轉發給task函數本身?
我重復執行功能的方法是否定期正確? 我特別希望它僅在完成后才睡覺,然后再重新啟動,而不是即使最后一個實例尚未完成也不會再次啟動。
僅當您實際包裝faketask
以包含可選的關鍵字參數時,才使用functools.partial
。 如果需要將關鍵字參數應用到其他函數( run_task
),則需要獨立執行。 例如,您可以在tasks
字典中為run_task
指定其他視run_task
:
tasks = {
'Task-1': faketask,
'Task-2': faketask,
'Task-3': (faketask, {'interval': 10)),
}
然后,調用run_task
的代碼將需要識別元組:
for taskname, taskfunc_maybe_with_options in tasks.items():
if isinstance(taskfunc_maybe_with_options, tuple):
taskfunc, options = taskfunc_maybe_with_options
else:
taskfunc = taskfunc_maybe_with_options
options = {}
tasklist.append(run_task(taskname, taskfunc, **options))
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.