簡體   English   中英

如何在 Python 3.8 中為 asyncio.gather 構建任務列表

[英]How to build list of tasks for asyncio.gather in Python 3.8

下面我附上了一個測試程序來演示我遇到的asyncio.gather拋出TypeError的問題。

我的目標:進行多個並發異步調用,以從連接到我的計算機的 USB 攝像頭陣列中將攝像頭圖像捕獲到文件中。 當所有相機都完成異步捕獲后,我想恢復處理。

此處顯示的異步協程take_image()“ffmpeg”應用程序進行系統調用,該應用程序將圖像從指定相機捕獲到指定文件。

import asyncio
import os
import subprocess
import time

async def take_image(camera_id, camera_name, image_file_path, image_counter):
    image_capture_tic = time.perf_counter()
    try:
        run_cmd = subprocess.run( ["ffmpeg", '-y', '-hide_banner', '-f', 'avfoundation', '-i', camera_id,
                                   '-frames:v', '1', '-f', 'image2', image_file_path], universal_newlines=True,
                                 stdout=subprocess.PIPE, stderr=subprocess.PIPE)  # Note, ffmpeg writes to stderr, not stdout!
    except Exception as e:
        print("Error: Unable to capture image for", image_file_path)
        return "NO IMAGE!"

    image_capture_toc = time.perf_counter()
    print(f"{image_counter}: Captured {camera_name} image in: {image_capture_toc - image_capture_tic:0.0f} seconds")
    return camera_name

下面顯示的main()例程獲取多個攝像頭的列表,並遍歷列表中的每個攝像頭, main() 使用asyncio.create_task()為每個攝像頭創建一個異步任務。 每個任務都添加到任務列表中。

一旦所有圖像捕獲任務都已啟動,我使用await asyncio.gather(tasks)等待它們完成。

async def main():
    tic = time.perf_counter()
    camera_list = [('0', 'FHD Camera #1'),  ('1', 'FHD Camera #2'), ('2', 'FHD Camera #3'), ]
    image_counter = 1
    tasks = []
    for camera_pair in camera_list:
        camera_id, camera_name = camera_pair
        image_file_name = 'img' + str(image_counter) + "-cam" + str(camera_id)  + "-" + camera_name + '.jpg'
        image_file_path = os.path.join("/tmp/test1/img", image_file_name)

        # schedule all image captures calls *concurrently*:
        tasks.append(asyncio.create_task(take_image(camera_id, camera_name, image_file_path, image_counter),
                     name=image_file_name))
        image_counter = image_counter + 1

    await asyncio.gather(tasks) # <-- This line throws a TypeError!
    toc = time.perf_counter()
    print(f"Captured list of {image_counter - 1} cameras in: {toc - tic:0.0f} seconds")

asyncio.run(main())

不幸的是,當我嘗試運行這個程序時,我收到了這個錯誤:

類型錯誤:不可散列類型:“列表”

和以下追溯:

Traceback (most recent call last):
  File "scratch_10.py", line 41, in <module>
    asyncio.run(main())
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/asyncio/runners.py", line 43, in run
    return loop.run_until_complete(main)
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/asyncio/base_events.py", line 608, in run_until_complete
    return future.result()
  File "scratch_10.py", line 36, in main
    await asyncio.gather(tasks)
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/asyncio/tasks.py", line 805, in gather
    if arg not in arg_to_fut:
TypeError: unhashable type: 'list'

我一直試圖通過 asyncio 的 3.8 文檔來解決問題,但我不明白出了什么問題。

如何讓每個 take_image 請求異步運行,然后在每個任務完成后在我的調用例程中恢復處理?

gather采用位置 arguments,而不是單個可迭代的參數。 你需要解開你的清單。

await asyncio.gather(*tasks)

你應該嘗試: (Task1,Task2,Task3)這就是我為任務所做的並且它有效

暫無
暫無

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

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