学无止境

少年辛苦终身事,莫向光阴惰寸功。——唐·杜荀鹤《题弟侄书堂》


Python多线程编程指南

1. 基础概念

1.1 进程与线程

  • 进程: 系统资源分配和调度的基本单位
  • 线程: CPU调度的最小单位,是进程的执行实体
  • 关系:
    • 一个进程可以包含多个线程
    • 线程共享进程的资源
    • 线程拥有自己的栈空间和寄存器

1.2 Python线程特点

  • 主线程是进程的第一个线程
  • 使用threading模块创建和管理线程
  • 受GIL(全局解释器锁)影响

2. 线程创建和管理

2.1 使用Thread类创建线程

from threading import Thread

# 方法1:传入目标函数
def task():
    print("Thread task")
    
thread = Thread(target=task)
thread.start()

# 方法2:传入带参数的函数
def task_with_args(name):
    print(f"Thread {name}")
    
thread = Thread(target=task_with_args, args=("Thread-1",))
thread.start()

2.2 继承Thread类创建线程

class MyThread(Thread):
    def __init__(self, name=None):
        super().__init__()
        self.name = name
        
    def run(self):
        print(f"Thread {self.name} is running")
        
thread = MyThread("Custom-Thread")
thread.start()

2.3 线程管理方法

# 获取当前线程
current = threading.current_thread()

# 获取线程名
name = thread.getName()
# 设置线程名
thread.setName("New-Name")

# 获取活动线程数
count = threading.active_count()

# 获取所有活动线程
threads = threading.enumerate()

# 等待线程结束
thread.join()

3. 线程同步机制

3.1 互斥锁(Lock)

from threading import Lock

# 创建锁
mutex = Lock()

def safe_task():
    # 获取锁
    mutex.acquire()
    try:
        # 临界区代码
        pass
    finally:
        # 释放锁
        mutex.release()
        
# 使用with语句(推荐)
def safe_task_with():
    with mutex:
        # 临界区代码
        pass

3.2 线程安全队列(Queue)

from queue import Queue

# 创建线程安全队列
q = Queue(maxsize=10)

# 生产者
def producer():
    while True:
        item = produce_item()
        q.put(item)

# 消费者
def consumer():
    while True:
        item = q.get()
        process_item(item)
        q.task_done()

4. 线程数据隔离

4.1 使用threading.local()

import threading

# 创建线程本地存储
local_data = threading.local()

def worker():
    # 每个线程都有独立的存储空间
    local_data.x = 0
    
    # 修改本地数据不会影响其他线程
    local_data.x += 1

5. 线程同步模式

5.1 生产者-消费者模式

from threading import Thread, Event
from queue import Queue

class Producer(Thread):
    def __init__(self, queue):
        super().__init__()
        self.queue = queue
    
    def run(self):
        while True:
            item = self.produce_item()
            self.queue.put(item)
            
class Consumer(Thread):
    def __init__(self, queue):
        super().__init__()
        self.queue = queue
    
    def run(self):
        while True:
            item = self.queue.get()
            self.process_item(item)
            self.queue.task_done()

6. 注意事项和最佳实践

6.1 GIL的影响

  • Python的GIL限制了多线程在CPU密集型任务上的性能
  • IO密集型任务仍然可以从多线程中受益
  • 考虑使用多进程来绕过GIL限制

6.2 死锁预防

  • 避免循环等待
  • 使用超时机制
  • 按固定顺序获取锁
  • 使用with语句自动释放锁

6.3 性能优化

  • 合理设置线程数量
  • 避免过多的线程同步操作
  • 使用线程池管理线程
  • 考虑使用异步IO替代多线程

6.4 调试技巧

  • 使用logging模块记录线程活动
  • 设置线程名便于调试
  • 使用threading.current_thread()确定当前线程
  • 使用threading.enumerate()监控活动线程

7. 示例应用

7.1 并发下载器

import threading
import requests
from queue import Queue

class DownloadWorker(Thread):
    def __init__(self, queue):
        super().__init__()
        self.queue = queue
        
    def run(self):
        while True:
            url = self.queue.get()
            try:
                self.download_file(url)
            finally:
                self.queue.task_done()
                
    def download_file(self, url):
        response = requests.get(url)
        # 处理下载内容

7.2 线程池实现

from concurrent.futures import ThreadPoolExecutor

def process_item(item):
    # 处理单个任务
    pass

# 创建线程池
with ThreadPoolExecutor(max_workers=4) as executor:
    # 提交任务
    future = executor.submit(process_item, item)
    # 获取结果
    result = future.result()