[英]How to build list of tasks for asyncio.gather in Python 3.8
Below I have attached a test program to demonstrate a problem I am having with asyncio.gather throwing a TypeError .下面我附上了一个测试程序来演示我遇到的asyncio.gather抛出TypeError的问题。
My objective: To make multiple concurrent asynchronous calls to capture camera images to files from an array of USB cameras attached to my computer.我的目标:进行多个并发异步调用,以从连接到我的计算机的 USB 摄像头阵列中将摄像头图像捕获到文件中。 When all cameras have completed their async captures, I want then resume processing.
当所有相机都完成异步捕获后,我想恢复处理。
The async coroutine take_image() shown here makes a system call to the "ffmpeg" application that captures an image from the specified camera to a specified file.此处显示的异步协程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
The main() routine shown below takes a list of multiple cameras, and iterating over each camera in the list, main() makes creates an asyncio task for each camera using asyncio.create_task() .下面显示的main()例程获取多个摄像头的列表,并遍历列表中的每个摄像头, main() 使用asyncio.create_task()为每个摄像头创建一个异步任务。 Each task is added to a list of tasks.
每个任务都添加到任务列表中。
Once all image capture tasks have been started, I await their completion using await asyncio.gather(tasks) .一旦所有图像捕获任务都已启动,我使用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())
Unfortunately, when I attempt to run this program, I am getting this error:不幸的是,当我尝试运行这个程序时,我收到了这个错误:
TypeError: unhashable type: 'list'类型错误:不可散列类型:“列表”
and the following Traceback:和以下追溯:
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'
I have been trying to puzzle through the 3.8 documentation on asyncio, but I don't understand what is wrong.我一直试图通过 asyncio 的 3.8 文档来解决问题,但我不明白出了什么问题。
How can I have each take_image request run asynchronously, and then resume processing in my calling routine once each task is complete?如何让每个 take_image 请求异步运行,然后在每个任务完成后在我的调用例程中恢复处理?
gather
takes positional arguments, not a single, iterable argument. gather
采用位置 arguments,而不是单个可迭代的参数。 You need to unpack your list.你需要解开你的清单。
await asyncio.gather(*tasks)
You should try: (Task1, Task2, Task3) That is what i did for tasks an it worked你应该尝试: (Task1,Task2,Task3)这就是我为任务所做的并且它有效
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.