Python多线程全面解析,从使用到GIL的底层逻辑

问题:

  • 现实场景:爬虫需要并发请求 100 个 URL / GUI 程序需避免界面卡顿
  • Python 的两种并发方案对比:多线程 (threading) vs 多进程 (multiprocessing)
  • 抛出核心问题:为什么 Python 多线程有时比单线程更慢?

Python多线程编程基础:快速上手

  • 创建线程的两种方式
    • 直接传入目标函数
    • 继承Tread类
python 复制代码
def worker(task_id):
    print(f"Processing task {task_id}")

thread = Thread(target=worker, args=(1,))


from threading import Thread

class MyThread(Thread):
    def run(self):
        print(f"Thread {self.name} is running")

thread = MyThread()
thread.start()  # 启动线程而非直接调用run()
  • 线程生命周期管理
    • start() vs join()
css 复制代码
threads = [Thread(target=worker, args=(i,)) for i in range(5)]
for t in threads: t.start()
for t in threads: t.join()  # 等待所有线程完成
  • 守护线程(daemon thread)的使用场景
ini 复制代码
t = Thread(target=background_task, daemon=True)
t.start()  # 主线程退出时自动终止

线程同步

当多个线程对共享资源进行操作时,可能会引发数据不一致的问题,这时就需要进行线程同步。Python提供了多种同步原语:

  • Lock锁
csharp 复制代码
import threading

counter = 0
lock = threading.Lock()
def increment():
    global counter
    for _ in range(100000):
        lock.acquire()  # 获取锁
        try:
            counter += 1
        finally:
            lock.release()  # 释放锁

# 创建并启动线程
threads = [threading.Thread(target=increment) for _ in range(2)]
for t in threads:
    t.start()
for t in threads:
    t.join()

print(f'最终结果: {counter}')  # 结果应为200000
  • RLock可重入锁 同一个线程可以多次获得RLock,适合在递归或者嵌套场景中使用
  • Semaphore信号量 用于控制同时访问资源的线程数量
python 复制代码
semaphore = threading.Semaphore(3)  # 最多允许3个线程同时访问
def worker():
    with semaphore:  # 获取信号量
        print('正在访问资源...')
  • Condition条件变量 用于线程间通信和协调
python 复制代码
condition = threading.Condition()

def consumer():
    with condition:
        condition.wait()  # 等待通知
        print('收到通知,开始消费')

def producer():
    with condition:
        print('生产完成,发送通知')
        condition.notify()  # 发送通知

线程间通信Queue vs 共享变量

线程间可以通过共享变量和队列Queue来交换数据,使用queue.Queue()是线程安全的方式

python 复制代码
from queue import Queue
import threading

def producer(queue):
    for item in range(5):
        queue.put(item)
        print(f'生产: {item}')

def consumer(queue):
    while True:
        item = queue.get()
        print(f'消费: {item}')
        queue.task_done()  # 通知队列任务已完成

q = Queue()
t1 = threading.Thread(target=producer, args=(q,))
t2 = threading.Thread(target=consumer, args=(q,), daemon=True)  # 守护线程

t1.start()
t2.start()
t1.join()  # 等待生产者线程完成
q.join()   # 等待队列中的所有任务被处理完
相关推荐
苏打水com9 分钟前
数据库进阶实战:从性能优化到分布式架构的核心突破
数据库·后端
间彧1 小时前
Spring Cloud Gateway与Kong或Nginx等API网关相比有哪些优劣势?
后端
间彧1 小时前
如何基于Spring Cloud Gateway实现灰度发布的具体配置示例?
后端
间彧1 小时前
在实际项目中如何设计一个高可用的Spring Cloud Gateway集群?
后端
间彧1 小时前
如何为Spring Cloud Gateway配置具体的负载均衡策略?
后端
间彧1 小时前
Spring Cloud Gateway详解与应用实战
后端
EnCi Zheng3 小时前
SpringBoot 配置文件完全指南-从入门到精通
java·spring boot·后端
烙印6013 小时前
Spring容器的心脏:深度解析refresh()方法(上)
java·后端·spring
Lisonseekpan3 小时前
Guava Cache 高性能本地缓存库详解与使用案例
java·spring boot·后端·缓存·guava
4 小时前
JUC专题 - 并发编程带来的安全性挑战之同步锁
后端