Python 线程 Threading

1. 基本概念

  • 线程(Thread):操作系统可调度的最小执行单元,属于进程(Process)的一部分。一个进程可以包含多个线程,线程之间共享进程的内存空间。
  • 进程(Process):具有独立内存空间和资源的运行实例。进程之间相互独立。

线程优点:

  • 轻量级,创建和切换开销小。
  • 适合 I/O 密集型任务。

线程缺点:

  • 多线程共享同一内存,需注意同步和数据安全。

2. 创建线程

2.1 函数式创建

from threading import Thread
import threading, time

def task(name, rounds=3):
    for i in range(rounds):
        time.sleep(1)
        print(f"线程 {name} 执行第 {i} 次")

if __name__ == '__main__':
    print("主线程开始")
    threads = [Thread(target=task, args=(f"T{i+1}",)) for i in range(2)]
    for t in threads: t.start()
    for t in threads: t.join()
    print("主线程结束")
  • Thread(target=..., args=...):指定目标函数和参数。
  • start():启动线程,调用 run() 方法。
  • join():阻塞主线程,直到该线程执行结束。

2.2 子类化创建

from threading import Thread
import threading, time

class MyThread(Thread):
    def __init__(self, name, rounds=3):
        super().__init__(name=name)
        self.rounds = rounds
    def run(self):
        for i in range(self.rounds):
            time.sleep(1)
            print(f"线程 {self.name} 执行第 {i} 次")

if __name__ == '__main__':
    print("主线程开始")
    threads = [MyThread(name=f"T{i+1}") for i in range(2)]
    for t in threads: t.start()
    for t in threads: t.join()
    print("主线程结束")
  • 通过继承 Thread 并重载 run() 方法,封装更强。

3. 数据共享与安全

  • 多线程共享全局变量或对象实例。
  • 示例
from threading import Thread
import time

a = 100

def add():
    global a
    a += 30
    print(f"加后: {a}")

def sub():
    global a
    a -= 50
    print(f"减后: {a}")

if __name__ == '__main__':
    print(f"初始: {a}")
    t1 = Thread(target=add)
    t2 = Thread(target=sub)
    t1.start(); t2.start()
    t1.join(); t2.join()
    print(f"最终: {a}")
  • 问题:线程执行顺序不确定,可能产生竞态条件(Race Condition),导致数据不一致。

3.1 锁(Lock)

from threading import Thread, Lock
import time

a = 100
lock = Lock()

def safe_add():
    global a
    with lock:
        tmp = a
        time.sleep(0.1)
        a = tmp + 30
    print(f"加后: {a}")

def safe_sub():
    global a
    with lock:
        tmp = a
        time.sleep(0.1)
        a = tmp - 50
    print(f"减后: {a}")

if __name__ == '__main__':
    threads = [Thread(target=safe_add), Thread(target=safe_sub)]
    for t in threads: t.start()
    for t in threads: t.join()
    print(f"最终: {a}")
  • 使用 LockRLock 保护临界区,确保同一时刻只有一个线程访问共享资源。

4. 生产者-消费者模型

通过 queue.Queue 实现线程间安全的数据交换:

方法 作用
put(item) 放入队列,队列满时阻塞
get() 取出队列,队列空时阻塞
task_done() 通知队列任务完成
join() 等待队列中所有任务完成
from queue import Queue
from threading import Thread
import time

class Producer(Thread):
    def __init__(self, queue):
        super().__init__()
        self.queue = queue
    def run(self):
        for i in range(3):
            print(f"生产: {i}")
            self.queue.put(i)
            time.sleep(1)
        print("生产者完成")

class Consumer(Thread):
    def __init__(self, queue):
        super().__init__()
        self.queue = queue
    def run(self):
        while True:
            item = self.queue.get()
            print(f"消费: {item}")
            self.queue.task_done()

if __name__ == '__main__':
    q = Queue()
    producers = [Producer(q) for _ in range(1)]
    consumers = [Consumer(q) for _ in range(1)]
    for c in consumers: c.daemon = True; c.start()
    for p in producers: p.start()
    for p in producers: p.join()
    q.join()
    print("主线程结束")
  • 设置消费者为守护线程(daemon),主线程退出后自动结束。

5. 小结

  1. 使用场景:I/O 密集型适合多线程,CPU 密集型推荐多进程(multiprocessing)。

  2. 同步工具LockRLockSemaphoreEventCondition 等。

  3. 线程池concurrent.futures.ThreadPoolExecutor 简化线程管理。

  4. 调试技巧:避免死锁、使用日志打印线程名与操作。

posted @ 2025-05-17 16:49  kyle_7Qc  阅读(132)  评论(0)    收藏  举报