当前位置: 首页 > 知识库问答 >
问题:

如何在Python 3.8中为asyncio.gather构建任务列表

李捷
2023-03-14

下面我附上了一个测试程序来演示asyncio.gather抛出类型错误的问题。

我的目标是:进行多个并发异步调用,从连接到我的计算机上的一组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()为每个摄影机创建一个asyncio任务。每个任务都会添加到任务列表中。

一旦所有的图像捕获任务已经开始,我等待他们完成使用等待asyncio.gather(任务)。

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())

不幸的是,当我试图运行这个程序,我得到了这个错误:

TypeError:不可损坏的类型:“列表”

以及以下回溯:

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请求异步运行,然后在每个任务完成后在调用例程中恢复处理?

共有2个答案

萧胜
2023-03-14

你应该试试:(Task1,Task2,Task3)这就是我为任务所做的,而且它起作用了

从焱
2023-03-14

gather接受位置参数,而不是一个单一的可编辑参数。你需要打开你的清单。

await asyncio.gather(*tasks)
 类似资料:
  • 问题内容: 好吧,我安装了elasticsearch-rails gem(版本0.1.5),并且可以清楚地看到gem文件中的任务。 但是当我跑步时 我得到这个错误。 运行也不显示任务。 elasticsearch正在运行,如果我卷曲它会回应我。 为什么这不起作用? 问题答案: 您需要创建elasticsearch.rake

  • 3.3.3 Android 任务 Android plugin 使用了同样的约定规则以和其他插件保持兼容,并且又添加了一些额外的引导任务: assemble 这个任务会汇集工程的所有输出。 check 这个任务会执行所有校验检查 connectedCheck 运行 checks 需要一个连接的设备或者模拟器,这些checks将会同时运行在所有连接的设备上。 deviceCheck 通过 API 连

  • 我有一个表,其列如下所示: 符号 区域 国家 位置 日期 计数 我创建了如下表: null 简单地说,我想要支持where子句中所有或任意数量列的表结构。 在卡桑德拉有可能做到这一点吗?

  • 执行 gradle tasks 命令会列出项目中所有任务. 这会显示项目中所有的默认任务以及每个任务的描述. 例 11.9 获取任务信息 gradle -q tasks 命令的输出 > gradle -q tasks ------------------------------------------------------------ All tasks runnable from root p

  • 3.3.2 Java 工程任务 Java plugin 创建了两个主要的任务,主要的引导任务都依赖他们。 assemble jar 这个任务创建所有输出 check test 这个任务运行所有测试 jar 任务直接或者间接的依赖其他任务:比如 classes 会编译所有Java代码. testClasses 会编译所有测试,但是它很少使用,因为 test 这个任务依赖它(和 classes 差不多

  • Android plugin 使用相同的约定以兼容其他插件,并且附加了标志性的 task,包括: assemble 组合项目所有输出 check 执行所有检查 connectedCheck 在一个连接的设备或者模拟器上执行检查,它们可以在所有连接的设备上并行执行检查 deviceCheck 通过 APIs 连接远程设备来执行检查,主要用于 CI(Continuos integration ,持续集