让你的Python并发飞起来:多线程开发实用技巧大全

一、为什么需要多线程?

在日常编程中,单线程程序执行任务时常常会因等待某些操作(比如文件读取、网络请求、数据库等)而"卡住"。多线程可以让你的程序一边处理A业务,一边等待/执行B业务,提升效率、改善用户体验。

常见使用场景:

  • 网络爬虫高并发抓取
  • 显示进度条同时下载/计算
  • 聊天、应用服务端、并发IO操作等

二、多线程的状态以及分类

线程创建之后,并不是始终保持一个状态的,其状态大概如下:

  • New 创建
  • Runnable 就绪。等待调度
  • Running 运行
  • Blocked 阻塞。阻塞可能在 Wait Locked Sleeping
  • Dead 消亡

线程的类型大致分为下面几种:

  • 主线程
  • 子线程
  • 守护线程(后台线程)
  • 前台线程

三、Python如何实现多线程?

Python的多线程主要依靠threading标准库模块。

来几个简单例子快速入门:

1. 最简单的多线程

python 复制代码
import threading

def worker():
    print("线程正在运行", threading.current_thread().name)

t = threading.Thread(target=worker, name='MyThread')
t.start() # 启动线程
t.join() # 等待线程结束

解释:

  • Thread 创建一个线程。
  • start() 启动线程,join() 主线程等待子线程结束。

2. 多线程并发

python 复制代码
import threading
import time

def task(name):
    print(f"{name} 开始工作")
    time.sleep(2)
    print(f"{name} 完成工作")

threads = []
for i in range(3):
    t = threading.Thread(target=task, args=(f'线程{i+1}',))
    t.start()
    threads.append(t)
for t in threads:
    t.join()
print("所有线程结束")

多个线程可同时执行,主线程等待所有线程完结。


四、认识GIL:为什么Python多线程不能提速CPU密集型任务?

GIL(全局解释器锁)是Python CPython解释器的"互斥锁",同一时刻只有一个线程能执行Python字节码。
所以io密集型(爬虫、文件、网络)多线程极其有效,但
CPU密集型任务
常无效(建议多进程)。

CPU密集型程序演示

python 复制代码
import threading
import time

def cpu_task():
    total = 0
    for _ in range(10**7):
        total += 1

threads = [threading.Thread(target=cpu_task) for _ in range(4)]
start = time.time()
for t in threads:
    t.start()
for t in threads:
    t.join()
print("用时:", time.time() - start)

可以试对比用单线程与多线程时间,几乎没有明显提升。


五、共享资源与锁机制

多线程易出现竞态条件问题:多个线程同时操作同一变量时,可能产生不可控的错误。

举例:线程安全导致的数据异常

python 复制代码
import threading

count = 0

def add():
    global count
    for _ in range(100000):
        count += 1

threads = [threading.Thread(target=add) for _ in range(2)]
for t in threads:
    t.start()
for t in threads:
    t.join()
print(count)  # 有很大概率小于200000

解决:加锁(Lock)

python 复制代码
lock = threading.Lock()
count = 0

def safe_add():
    global count
    for _ in range(100000):
        with lock:
            count += 1

threads = [threading.Thread(target=safe_add) for _ in range(2)]
for t in threads:
    t.start()
for t in threads:
    t.join()
print(count)  # 必定是200000

with lock: 能保证同一时刻只有一个线程进入代码块,杜绝数据错乱。


六、更高级:守护线程与条件变量

1. 守护线程(Daemon Thread)

主线程退出时,守护线程自动结束。

python 复制代码
import threading
import time

def worker():
    while True:
        print('工作中...')
        time.sleep(1)

t = threading.Thread(target=worker)
t.daemon = True  # 设置为守护线程,主线程结束时子线程也会退出
t.start()
time.sleep(3)
print("主线程结束")  # 子线程会跟随退出

2. Thread子类实现(面向对象)

python 复制代码
class MyThread(threading.Thread):
    def run(self):
        print("自定义线程运行")

t = MyThread()
t.start()
t.join()

3. 条件变量/信号量(Condition/Semaphore)

用于更复杂的线程同步和通信,可以实现"生产者-消费者"模式、任务队列处理等。

python 复制代码
import threading
import time

condition = threading.Condition()
data = []

def producer():
    for i in range(3):
        with condition:
            data.append(i)
            print("生产:", i)
            condition.notify()
            time.sleep(1)

def consumer():
    for _ in range(3):
        with condition:
            while not data:
                condition.wait()
            print("消费:", data.pop(0))

t1 = threading.Thread(target=producer)
t2 = threading.Thread(target=consumer)
t1.start()
t2.start()
t1.join()
t2.join()

七、典型应用场景案例

1. 多线程爬虫IO密集案例

python 复制代码
import threading
import requests

def fetch(url):
    resp = requests.get(url)
    print(f"{url} 响应长度: {len(resp.text)}")

urls = [
    'https://www.baidu.com',
    'https://www.python.org',
    'https://www.github.com',
]
threads = [threading.Thread(target=fetch, args=(u,)) for u in urls]
for t in threads:
    t.start()
for t in threads:
    t.join()
print("所有网页抓取完成")

大大加快多个网页的抓取速度。

2. 线程池简化并发任务

官方库concurrent.futures.ThreadPoolExecutor推荐用法:

python 复制代码
from concurrent.futures import ThreadPoolExecutor

def square(n):
    return n*n

with ThreadPoolExecutor(max_workers=5) as executor:
    results = list(executor.map(square, range(10)))
print(results)

更方便地发起大量并发任务和收集异步结果。


点个赞,关注我获取更多实用 Python 技术干货!如果觉得有用,记得收藏本文!

相关推荐
叫我:松哥42 分钟前
python案例:基于python 神经网络cnn和LDA主题分析的旅游景点满意度分析
人工智能·python·神经网络·数据挖掘·数据分析·cnn·课程设计
2202_756749692 小时前
01 基于sklearn的机械学习-机械学习的分类、sklearn的安装、sklearn数据集及数据集的划分、特征工程(特征提取与无量纲化、特征降维)
人工智能·python·机器学习·分类·sklearn
我不吃饼干2 小时前
在 React 中实现倒计时功能会有什么坑
前端·react.js
小小小小宇2 小时前
前端PerformanceObserver
前端
王者鳜錸2 小时前
PYTHON从入门到实践-18Django从零开始构建Web应用
前端·python·sqlite
拾光拾趣录2 小时前
ES6到HTTPS全链路连环拷问,99%人第3题就翻车?
前端·面试
冗量2 小时前
PPT自动化 python-pptx - 8: 文本(text)
python·自动化·powerpoint
超级晒盐人3 小时前
用落霞归雁的思维框架推导少林寺用什么数据库?
java·python·系统架构·学习方法·教育电商
haaaaaaarry3 小时前
Element Plus常见基础组件(二)
开发语言·前端·javascript
AI_RSER3 小时前
第一篇:【Python-geemap教程(三)上】3D地形渲染与Landsat NDVI计算
开发语言·python·3d·信息可视化·遥感·gee