让你的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 技术干货!如果觉得有用,记得收藏本文!

相关推荐
Justin3go1 小时前
两年后又捣鼓了一个健康类小程序
前端·微信小程序
superkcl20221 小时前
【JAVA】【Stream流】
java·windows·python
明月与玄武2 小时前
Python爬虫工作基本流程及urllib模块详解
开发语言·爬虫·python
一ge科研小菜鸡3 小时前
编程语言的演化与选择:技术浪潮中的理性决策
java·c语言·python
船长@Quant3 小时前
Plotly图表全面使用指南 -- Displaying Figures in Python
python·plotly·图表·图形库
acstdm3 小时前
DAY 35 模型可视化与推理
人工智能·python
巴巴_羊3 小时前
xss和csrf
前端·xss·csrf
19893 小时前
【Dify精讲】第12章:性能优化策略与实践
人工智能·python·深度学习·性能优化·架构·flask·ai编程
华子w9089258593 小时前
基于 Python Web 应用框架 Django 的在线小说阅读平台设计与实现
前端·python·django