摘要:本文介绍了 Python 并发编程的三种主要方式:多线程、多进程和异步编程。多线程适用于 I/O 密集型任务,通过线程池管理资源;多进程突破了 GIL 限制,适合 CPU 密集型任务,进程池可优化资源管理;异步编程基于事件循环,适合大规模 I/O 密集型任务,支持异步上下文管理和异步 I/O。文中通过示例代码展示了每种并发模型的使用方法,并强调了线程安全、资源管理和异常处理的重要性。

关键词:Python 并发编程;多线程;多进程;异步编程;线程池;进程池;异步 I/O

人工智能助手:Kimi


一、多线程(Threading)

多线程是并发编程中最常见的技术之一。Python 的 threading 模块提供了线程的基本功能,允许程序同时运行多个线程。

线程的基本使用

线程可以用于执行耗时的操作,例如文件 I/O、网络请求等,从而避免阻塞主线程。

示例代码

import threading
import time

class MyThread(threading.Thread):
    def __init__(self, name, duration):
        super().__init__()
        self.name = name
        self.duration = duration

    def run(self):
        print(f"Thread {self.name} is starting.")
        time.sleep(self.duration)
        print(f"Thread {self.name} has finished.")

# 创建线程
thread1 = MyThread("Thread-1", 2)
thread2 = MyThread("Thread-2", 3)

# 启动线程
thread1.start()
thread2.start()

# 等待线程完成
thread1.join()
thread2.join()

print("All threads have finished.")

输出

Thread Thread-1 is starting.
Thread Thread-2 is starting.
Thread Thread-1 has finished.
Thread Thread-2 has finished.
All threads have finished.
线程同步

多线程编程中,线程之间可能会共享资源,这可能导致数据竞争和线程安全问题。Python 提供了多种同步机制,如锁(Lock)、信号量(Semaphore)、事件(Event)等。

示例代码

import threading

class Counter:
    def __init__(self):
        self.value = 0
        self.lock = threading.Lock()

    def increment(self):
        with self.lock:
            self.value += 1

# 创建共享资源
counter = Counter()

def worker():
    for _ in range(10000):
        counter.increment()

# 创建线程
threads = [threading.Thread(target=worker) for _ in range(10)]

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

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

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

输出

Final counter value: 100000
线程池

线程池可以有效地管理线程资源,避免频繁创建和销毁线程的开销。Python 的 concurrent.futures 模块提供了线程池的实现。

示例代码

import concurrent.futures
import time

def task(n):
    print(f"Task {n} is starting.")
    time.sleep(n)
    return f"Task {n} has finished."

# 创建线程池
with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
    futures = [executor.submit(task, i) for i in range(1, 4)]

    for future in concurrent.futures.as_completed(futures):
        print(future.result())

输出

Task 1 is starting.
Task 2 is starting.
Task 1 has finished.
Task 3 is starting.
Task 2 has finished.
Task 3 has finished.

二、多进程(Multiprocessing)

多线程在 Python 中受到全局解释器锁(GIL)的限制,这意味着在单个 Python 进程中,同一时刻只能有一个线程执行 Python 字节码。为了充分利用多核 CPU 的性能,可以使用多进程。

Python 的 multiprocessing 模块提供了进程的基本功能,允许程序同时运行多个进程。

进程的基本使用

进程可以用于执行 CPU 密集型任务,例如计算密集型操作。

示例代码

import multiprocessing
import time

def worker(name):
    print(f"Process {name} is starting.")
    time.sleep(2)
    print(f"Process {name} has finished.")

# 创建进程
processes = [multiprocessing.Process(target=worker, args=(f"Process-{i}",)) for i in range(3)]

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

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

print("All processes have finished.")

输出

Process Process-0 is starting.
Process Process-1 is starting.
Process Process-2 is starting.
Process Process-0 has finished.
Process Process-1 has finished.
Process Process-2 has finished.
All processes have finished.
进程池

进程池可以有效地管理进程资源,避免频繁创建和销毁进程的开销。Python 的 multiprocessing 模块提供了进程池的实现。

示例代码

import multiprocessing
import time

def task(n):
    print(f"Task {n} is starting.")
    time.sleep(n)
    return f"Task {n} has finished."

# 创建进程池
with multiprocessing.Pool(processes=3) as pool:
    results = pool.map(task, range(1, 4))

    for result in results:
        print(result)

输出

Task 1 is starting.
Task 2 is starting.
Task 1 has finished.
Task 3 is starting.
Task 2 has finished.
Task 3 has finished.

三、异步编程(Asyncio)

异步编程是一种基于事件循环的并发模型,适用于 I/O 密集型任务。Python 的 asyncio 模块提供了异步编程的支持。

异步函数

异步函数使用 async def 定义,可以使用 await 调用其他异步函数。

示例代码

import asyncio

async def task(name, duration):
    print(f"Task {name} is starting.")
    await asyncio.sleep(duration)
    print(f"Task {name} has finished.")

async def main():
    await asyncio.gather(
        task("Task-1", 2),
        task("Task-2", 3),
        task("Task-3", 1)
    )

# 运行异步主函数
asyncio.run(main())

输出

Task Task-1 is starting.
Task Task-2 is starting.
Task Task-3 is starting.
Task Task-3 has finished.
Task Task-1 has finished.
Task Task-2 has finished.
异步上下文管理器

异步上下文管理器可以用于异步资源的管理,例如异步文件操作或网络连接。

示例代码

import asyncio

class AsyncContextManager:
    async def __aenter__(self):
        print("Entering the context.")
        return self

    async def __aexit__(self, exc_type, exc, tb):
        print("Exiting the context.")

    async def do_something(self):
        print("Doing something inside the context.")

async def main():
    async with AsyncContextManager() as manager:
        await manager.do_something()

# 运行异步主函数
asyncio.run(main())

输出

Entering the context.
Doing something inside the context.
Exiting the context.
异步 I/O

asyncio 提供了异步 I/O 的支持,可以用于异步文件操作和网络请求。

示例代码

import asyncio

async def fetch_data(url):
    print(f"Fetching data from {url}")
    await asyncio.sleep(2)  # 模拟网络请求
    return f"Data from {url}"

async def main():
    url = "https://example.com"
    data = await fetch_data(url)
    print(data)

# 运行异步主函数
asyncio.run(main())

输出

Fetching data from https://example.com
Data from https://example.com

二、并发编程的注意事项

  • 线程安全:在多线程环境中,需要使用锁或其他同步机制来避免数据竞争。
  • GIL 限制:Python 的全局解释器锁(GIL)限制了多线程的性能,对于 CPU 密集型任务,建议使用多进程。
  • 资源管理:在并发编程中,需要合理管理资源,避免资源泄漏。
  • 异常处理:在异步编程中,需要正确处理异常,避免程序崩溃。

全文总结

本文详细介绍了 Python 并发编程的三种主要方式:多线程、多进程和异步编程。多线程通过 threading 模块实现,适用于 I/O 密集型任务,但受限于全局解释器锁(GIL),无法充分利用多核 CPU。多进程通过 multiprocessing 模块实现,突破了 GIL 限制,适合 CPU 密集型任务,能够充分利用多核 CPU 的性能。异步编程通过 asyncio 模块实现,基于事件循环,适合大规模 I/O 密集型任务,能够高效处理大量并发的 I/O 操作。文中通过具体的示例代码展示了每种并发模型的使用方法,并强调了线程安全、资源管理和异常处理的重要性。在实际开发中,开发者需要根据具体任务的性质(I/O 密集型或 CPU 密集型)选择合适的并发模型,以提高程序的效率和响应能力。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐