python多线程

  • 多线程的原理是在同一进程内创建多个线程来执行不同的任务,这些线程共享同一进程的资源,包括内存空间、文件句柄等。每个线程拥有独立的执行路径,可以并行执行任务,从而提高程序的效率。
  • 在代码中,通过调用 threading.Thread 类创建了多个线程对象。每个线程对象都有一个 target 参数,指定了该线程要执行的函数,以及一个 args 参数,传入了该函数所需的参数。在调用 thread.start() 方法后,系统会为该线程分配资源,并执行指定的函数。
  • 由于操作系统会分配给每个线程一定的时间片来执行任务,因此多个线程可以在同一时刻并发执行不同的任务。这样,在处理大量图片文件时,可以同时加载、处理和保存多张图片,从而提高了整体的处理效率。

单线程和多线程对比

import threading
import time

# 假设这是一批大型图片文件列表
image_files = ["image1.jpg", "image2.jpg", "image3.jpg", "image4.jpg", "image5.jpg"]

# 定义一个函数,用于处理图片的整个流程(加载、处理、保存)
def process_image_workflow(image_file):
    # 这里用 sleep 来模拟 加载、处理、保存 时间 
     time.sleep(6)

# 定义一个函数,用于单线程处理图片
def process_images_single_threaded(image_files):
    start_time = time.time()
    for image_file in image_files:
        process_image_workflow(image_file)
    end_time = time.time()
    print(f"单线程处理图片总耗时:{end_time - start_time} 秒")             # 30.148472547531128 秒

# 定义一个函数,用于创建并启动线程来处理图片
def process_images_threaded(image_files):
    start_time = time.time()
    threads = []  # 用于存储线程对象
    for image_file in image_files:
        thread = threading.Thread(target=process_image_workflow, args=(image_file,))
        threads.append(thread)
        thread.start()   # 启动线程,使其开始执行 process_image_workflow 函数中定义的任务

    # 等待所有线程执行完成
    for thread in threads:
        thread.join()
    end_time = time.time()
    print(f"多线程处理图片总耗时:{end_time - start_time} 秒")             # 6.02411675453186 秒

if __name__ == "__main__":
    print("单线程处理图片:")
    process_images_single_threaded(image_files)   
    print("\n多线程处理图片:")
    process_images_threaded(image_files)

image-20240406213401686

image-20240406213431224

如何确定几个线程

确定使用多少个线程来处理任务通常是一个复杂的问题,需要考虑多个因素,包括但不限于以下几点:

  1. 任务的性质和工作负载:不同类型的任务可能对线程数量的需求不同。有些任务可能是 CPU 密集型的,需要更多的线程来充分利用 CPU 的计算资源;而有些任务可能是 I/O 密集型的,需要更多的线程来充分利用 I/O 操作的并行性。
  2. 系统资源:系统的硬件资源限制了可以同时运行的线程数量。例如,CPU 的核心数、内存大小等都会影响线程的数量选择。
  3. 线程间的竞争和同步:过多的线程可能导致线程间频繁地竞争资源,造成性能下降。同时,线程间的同步也会增加复杂性和开销。因此,需要权衡线程数量和同步机制的选择。
  4. 任务的分解和并行度:如果任务可以很容易地分解成多个独立的子任务,并且这些子任务可以并行执行,那么就可以考虑增加线程数量来提高并行度,从而加快整体处理速度。
  5. 实验和性能测试:最终确定线程数量通常需要通过实验和性能测试来确定。可以尝试不同数量的线程,并测量处理任务所需的时间,以找到最佳的线程数量。

总的来说,确定线程数量需要综合考虑任务本身的性质、系统资源限制、线程间的竞争和同步等因素,并通过实验和性能测试来确定最佳的线程数量。

如果图片数量增加到一百张,那么就会创建一百个线程来处理这些图片。这种方法在图片数量较少时可能是可行的,但在大规模处理时可能会遇到一些问题:

  1. 资源消耗:创建大量线程会消耗系统资源,包括内存和CPU时间片。如果线程数量过多,可能会导致系统性能下降。
  2. 竞争和同步:过多的线程可能会导致线程间频繁竞争资源,例如CPU和内存。同时,线程间的同步也可能增加复杂性和开销。
  3. 性能稳定性:大量线程的创建和管理可能会导致性能不稳定,例如线程间的切换开销和调度延迟等问题。

针对大规模图片处理,你可以考虑以下优化策略:

  1. 线程池:使用线程池来管理线程的创建和销毁,避免频繁创建和销毁线程带来的开销。
  2. 任务分批:将大量图片分批处理,每批处理一定数量的图片,然后使用线程池来处理每一批图片。
  3. 异步处理:使用异步编程模型,例如使用asyncio库来实现异步IO操作,提高程序的并发性能。
  4. 资源限制:根据系统资源情况和性能测试结果,设定合理的线程数量上限,避免过多线程导致的资源竞争和性能下降。

综上所述,针对大规模图片处理,合理地管理线程数量和资源是非常重要的,需要根据实际情况进行优化和调整。

根据以下准则来设置多线程的数量:

IO密集型任务:一般情况下,线程数应该大于CPU核心数,以充分利用CPU等待IO操作的时间。可以根据经验选择一个适当的倍数,例如2倍或4倍。

计算密集型任务:由于Python的GIL(Global Interpreter Lock)限制了多线程中的并行计算,所以多线程并不适合用于加速计算密集型任务。在这种情况下,使用多进程或协程可能更合适。

以下是设置线程数量的示例代码:

import threading

# 获取CPU核心数
cpu_count = threading.cpu_count()

# 设置线程数量
thread_count = cpu_count * 2  # 可根据实际情况进行调整

运行程序:

import threading

# 创建并启动线程
def run_task():
    # TODO: 编写具体的任务逻辑
    pass

threads = []
for _ in range(thread_count):
    thread = threading.Thread(target=run_task)
    thread.start()
    threads.append(thread)

# 等待所有线程执行完毕
for thread in threads:
    thread.join()
posted @   德琪  阅读(120)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
历史上的今天:
2023-04-26 【电脑删不掉文件或文件夹】
点击右上角即可分享
微信分享提示