簡體   English   中英

從字典將* args和** kwargs傳遞給asyncio定期包裝器函數

[英]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是如何使用方面有困難。

所以我的問題是

  1. 我該怎么做,這是完成我要嘗試的工作的適當方法嗎?

  2. 我如何以盡可能簡單的方式(在新任務可以輕松添加的情況下)為tasks字典中的特定函數提供* args和** kwarg,並通過包裝將它們轉發給task函數本身?

  3. 我重復執行功能的方法是否定期正確? 我特別希望它僅在完成后才睡覺然后再重新啟動,而不是即使最后一個實例尚未完成也不會再次啟動。

僅當您實際包裝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.

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