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()   # 等待队列中的所有任务被处理完
相关推荐
Java爱好狂.7 小时前
Java初学者如何一周速通SpringBoot!
java·spring boot·后端·spring·高并发·架构师·java面试
马良神笔9 小时前
2026 年Rag最近技术前沿总结
后端·python·django
程序猿DD9 小时前
同样10美元,OpenDesign和Command Code的DeepSeek V4.1 Flash额度到底有多少?
后端
高频因子挖掘机9 小时前
A股量化从日线升级到5分钟线:数据量增加后最先暴露哪些工程问题?
后端·github·api
高频因子挖掘机10 小时前
历史行情返回顺序变了,为什么按行号计算指标很危险?
后端·github·api
团子哒哒11 小时前
数组、切片和Map
后端
专注仿真11 小时前
ThinkPHP6 API接口开发实例:从零搭建RESTful风格接口
后端·php·restful
开心猴爷11 小时前
应对iOS审核4.3:可以使用 IpaGuard 来给属性名混淆的技术细节与平衡之道
后端·ios
1m5555555512 小时前
RAG 工程实战(五):正确知识已经进入 Prompt,为什么大模型还是会答错?
后端·面试
易小尊12 小时前
我的模型在 65% 以上时准得可怕,在 50% 时像在掷硬币
后端