白骑士的Python教学高级篇 3.1 多线程与多进程

系列目录

上一篇:白骑士的Python教学进阶篇 2.4 高级数据结构

        在现代编程中,提升程序性能和处理能力的常见方法之一是并发编程,通过同时执行多个任务来提高效率。Python中主要有两种并发方式:多线程和多进程。理解它们的概念、差异以及如何在Python中使用这些技术是成为高级Python开发者的重要一步。

线程与进程的概念

        线程:操作系统能够进行运算调度的最小单位,一个进程可以包含一个或多个线程。线程之间共享进程的资源,如内存和文件句柄,但每个线程有自己的栈和寄存器等私有数据。多线程适合I/O密集型任务,因为线程可以在等待I/O操作完成时执行其他任务。

        进程:资源分配的基本单位,一个进程包含了程序的代码、数据、内存空间和资源(如文件句柄、信号等)。每个进程都有自己的独立内存空间,进程间的数据共享需要通过进程间通信(IPC)机制。多进程适合CPU密集型任务,因为每个进程都有独立的内存空间和GIL限制,不会互相干扰。

threading模块

        Python的 ‘threading’ 模块提供了创建和控制线程的方法。使用 ‘threading’ 模块可以轻松地在程序中创建多个线程,实现并发执行。

创建线程

        创建线程的最简单方式是实例化 ‘threading.Thread’ 类,然后调用 ‘start()’ 方法启动线程,例如:

import threading


def worker():
    print("Thread is running")


# 创建线程
thread = threading.Thread(target=worker)

# 启动线程
thread.start()

# 等待线程完成
thread.join()

线程同步

        由于线程共享全局变量,因此需要考虑线程同步的问题,以避免竞争条件。‘threading’ 模块提供了多种同步原语,如锁(Lock)、条件变量(Condition)和事件(Event)。

import threading


# 创建一个锁对象
lock = threading.Lock()
counter = 0


def worker():
    global counter
    with lock:  # 使用锁来确保对共享资源的互斥访问
        counter += 1


threads = [threading.Thread(target=worker) for _ in range(10)]

# 启动所有线程
for thread in threads:
    thread.start()

# 等待所有线程完成
for thread in threads:
    thread.join()

print(f"Counter value: {counter}")

multiprocessing模块

        Python的 ‘multiprocessing’ 模块允许创建多个进程,每个进程运行在独立的内存空间中,从而绕过GIL的限制。这使得 ‘multiprocessing’ 模块特别适合CPU密集型任务。

创建进程

        与 ‘threading’ 模块类似,可以通过实例化 ‘multiprocessing.Process’ 类来创建进程,例如:

import multiprocessing


def worker():
    print("Process is running")


# 创建进程
process = multiprocessing.Process(target=worker)

# 启动进程
process.start()

# 等待进程完成
process.join()

进程间通信

        由于每个进程都有自己的内存空间,进程间通信(IPC)是必须的。‘multiprocessing’ 模块提供了队列(Queue)和管道(Pipe)等IPC机制。

import multiprocessing


def worker(queue):
    queue.put("Hello from process")


# 创建队列
queue = multiprocessing.Queue()

# 创建进程
process = multiprocessing.Process(target=worker, args=(queue,))

# 启动进程
process.start()

# 等待进程完成
process.join()

# 从队列中获取数据
print(queue.get())

共享内存

        ‘multiprocessing’ 模块还提供了共享内存的机制,可以通过 ‘Value’ 和 ‘Array’ 实现进程间的数据共享,例如:

import multiprocessing


def worker(shared_counter):
    with shared_counter.get_lock():  # 获取锁
        shared_counter.value += 1


# 创建共享内存对象
counter = multiprocessing.Value('i', 0)

processes = [multiprocessing.Process(target=worker, args=(counter,)) for _ in range(10)]

# 启动所有进程
for process in processes:
    process.start()

# 等待所有进程完成
for process in processes:
    process.join()

print(f"Counter value: {counter.value}")

GIL与并发编程

        全局解释器锁(GIL)是CPython解释器的一个机制,它确保同一时间只有一个线程执行Python字节码。这意味着即使在多线程程序中,CPU密集型任务也无法并行执行,从而限制了多线程的性能。

        GIL的存在主要是为了简化CPython解释器的内存管理,避免多线程同时访问共享内存时的竞态条件。但GIL对于I/O密集型任务影响较小,因为线程在等待I/O操作时可以释放GIL,让其他线程继续执行。

        为了提高CPU密集型任务的并发性,开发者通常采用多进程编程,因为每个进程都有自己的独立内存空间和GIL,不会受到限制。

多线程的优点与缺点

优点:

  • 线程创建和切换的开销较小;
  • 适合I/O密集型任务;
  • 线程共享内存空间,数据共享较为方便。

缺点:

  • 受GIL限制,CPU密集型任务无法并行执行;
  • 线程间共享数据需要同步,增加了编程复杂性。

多进程的优点与缺点

优点:

  • 每个进程都有独立内存空间,不受GIL限制;
  • 适合CPU密集型任务;
  • 进程间隔离性好,避免了数据竞争问题。

缺点:

  • 进程创建和切换的开销较大;
  • 进程间通信(IPC)相对复杂。

总结

        多线程和多进程是实现并发编程的重要手段,各有其适用场景和优缺点。在Python中,‘threading’ 模块适用于I/O密集型任务,而 ‘multiprocessing’ 模块则更适合CPU密集型任务。理解并灵活运用这些技术可以大幅提升程序的性能和处理能力,满足各种复杂应用的需求。

        通过本文的介绍,相信已经对Python中的多线程与多进程有了较为全面的了解。在实际开发中,根据具体的应用场景选择合适的并发方式,合理地利用线程和进程的优势,才能编写出高效、可靠的并发程序。

下一篇:白骑士的Python教学高级篇 3.2 网络编程​​​​​​​

  • 15
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

白骑士所长

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值