python多线程编程(二)

本文介绍了Python并发编程中concurrent.futures模块的Executor接口,重点讲解了ThreadPoolExecutor和ProcessPoolExecutor的用法,包括submit和map方法,以及它们在处理CPU密集型和IO密集型任务中的应用。通过实例演示了如何创建线程池和进程池执行任务,并确保顺序处理视频帧以保持帧序不变。
摘要由CSDN通过智能技术生成


python 多线程编程(一)

这一篇主要记录线程池的基本知识和用法。

一般计算(CPU)密集型任务适合多进程,IO密集型任务适合多线程;

concurrent.futures

异步执行可以由 ThreadPoolExecutor 使用线程或由 ProcessPoolExecutor 使用单独的进程来实现。 两者都是实现抽象类 Executor 定义的接口。

Executor 对象

class concurrent.futures.Executor:抽象类提供异步执行调用方法。要通过它的子类调用,而不是直接调用。

  • submit(fn, /, *args, **kwargs): 调度可调用对象 fn,以 fn(*args, **kwargs) 方式执行并返回一个代表该可调用对象的执行的 Future 对象。
  • map(fn, *iterables, timeout=None, chunksize=1):返回一个将 fn 应用于 iterable 的每一项,并产生其结果的迭代器。fn 是异步执行的并且可以并发对 fn 的多个调用。
  • shutdown(wait=True, *, cancel_futures=False): 当待执行的 future 对象完成执行后向执行者发送信号,它就会释放正在使用的任何资源。如果 wait 为 True 则此方法只有在所有待执行的 future 对象完成执行且释放已分配的资源后才会返回;如果 wait 为 False,方法立即返回,所有待执行的 future 对象完成执行后会释放已分配的资源。

Future对象

Future 类将可调用对象封装为异步执行。Future 实例由 Executor.submit() 创建。

ThreadPoolExecutor

ThreadPoolExecutor 是 Executor 的子类,它使用线程池来异步执行调用。

class concurrent.futures.ThreadPoolExecutor(max_workers=None, thread_name_prefix=‘’, initializer=None, initargs=())

Executor 子类使用最多 max_workers 个线程的线程池来异步执行调用。

代码示例

首先,先导入concurrent.futures库,然后定义一个模拟函数;接下来使用ThreadPoolExecutor创建一个线程池,随后创建一个包含多个任务的任务队列task_queue,然后用submit方法将每个任务提交到线程池中执行。最后调用shutdown方法等待所有任务完成并关闭线程池。

import concurrent.futures
 
# 模拟的任务函数
def task_function(task):
    print(f"Processing task: {task}")
 
# 创建线程池
with concurrent.futures.ThreadPoolExecutor() as executor:
    # 创建一个任务队列
    task_queue = ["Task 1", "Task 2", "Task 3", "Task 4", "Task 5"]
 
    # 提交任务到线程池
    for task in task_queue:
        executor.submit(task_function, task)
 
    # 等待所有任务完成
    executor.shutdown()

上述的方法还可以使用map来处理队列中的多个任务。

import concurrent.futures
 
# 模拟的任务函数
def task_function(task):
    print(f"Processing task: {task}")
    return task.upper()
 
# 创建线程池
with concurrent.futures.ThreadPoolExecutor() as executor:
    # 创建一个任务队列
    task_queue = ["Task 1", "Task 2", "Task 3", "Task 4", "Task 5"]
 
    # 使用map方法处理任务队列
    results = executor.map(task_function, task_queue)
 
    # 获取任务的执行结果
    for result in results:
        print(f"Task result: {result}")

ProcessPoolExecutor

ProcessPoolExecutor 类是 Executor 的子类,它使用进程池来异步地执行调用。 ProcessPoolExecutor 会使用 multiprocessing 模块,这允许它绕过 全局解释器锁 但也意味着只可以处理和返回可封存的对象。

__main__ 模块必须可以被工作者子进程导入。这意味着ProcessPoolExecutor不可以工作在交互式解释器中。

class concurrent.futures.ProcessPoolExecutor(max_workers=None, mp_context=None, initializer=None, initargs=(), max_tasks_per_child=None)
异步地执行调用的 Executor 子类使用最多 max_workers 个进程的进程池。 如果max_workers为None或未给出,它将默认为机器的处理器个数。 如果 max_workers小于等于0,则将引发ValueError。

示例

对视频文件想要并行处理,同时还得保证处理后的帧顺序不变。使用submit方法可能会出现帧乱序的情况,可以使用map方法。map方法会按照任务在任务队列中的顺序返回结果。所以,先按顺序读取原视频的所有帧,将其放到一个队列中,然后作为map的参数传进去。

import cv2  
import concurrent.futures  
import queue  
import numpy as np  
 
# 视频帧处理函数  
def process_frame(frame):  
    # 将图像转为灰度图  
    frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)  
    return frame  
 
# 读取视频文件  
cap = cv2.VideoCapture('your_video_path.mp4')
frames = []
while True:
    ret, frame =cap.read()
    if not ret:
        break
    frames.append(frame)
 
# 获取视频的帧率、帧大小和总帧数  
fps = cap.get(cv2.CAP_PROP_FPS)  
frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))  
frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))  
frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))  
print(fps, frame_width, frame_height, frame_count)
 
# 创建输出视频文件  
fourcc = cv2.VideoWriter_fourcc(*'mp4v')  # 根据实际情况选择合适的编码器  
out = cv2.VideoWriter('your_new_video_path.mp4', fourcc, fps, (frame_width, frame_height), isColor=False) #灰度图视频
 
# 创建线程池和队列  
with concurrent.futures.ThreadPoolExecutor() as executor:
    feature_results = executor.map(process_frame, frames)
    for result in feature_results:
        # print(type(result), result.shape, result)
        out.write(result)
cap.release()
out.release()  # 释放输出视频文件句柄
  • 28
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

马鹤宁

谢谢

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值