好的!下面给你一份关于 Python多线程 的学习系列内容,涵盖基本概念、线程创建、线程同步、常见问题和示例代码,帮助你快速理解和掌握Python多线程编程。


Python学习系列之多线程


一、多线程基础概念

  • 线程(Thread) 是操作系统能够进行运算调度的最小单位,属于轻量级进程。
  • 多线程允许程序并发执行多个任务,提高程序效率,特别适合I/O密集型任务。
  • Python的多线程受到 GIL(全局解释器锁)限制,CPU密集型任务效果有限,但对I/O操作仍然有效。

二、Python中多线程的实现方式

  • 通过 threading 模块实现多线程。
  • 线程由 Thread 类创建和管理。

三、线程创建与启动示例

import threading
import time

def worker(num):
    print(f"线程 {num} 开始工作")
    time.sleep(2)
    print(f"线程 {num} 结束工作")

# 创建线程
thread1 = threading.Thread(target=worker, args=(1,))
thread2 = threading.Thread(target=worker, args=(2,))

# 启动线程
thread1.start()
thread2.start()

# 等待线程结束
thread1.join()
thread2.join()

print("所有线程完成")

四、线程同步

多线程同时访问共享资源可能导致数据竞争,需用同步机制。

1. Lock(互斥锁)

import threading

lock = threading.Lock()
counter = 0

def task():
    global counter
    for _ in range(1000):
        lock.acquire()
        counter += 1
        lock.release()

threads = [threading.Thread(target=task) for _ in range(10)]
for t in threads:
    t.start()
for t in threads:
    t.join()

print(f"最终计数值: {counter}")

2. 使用 with 语句更优雅

def task():
    global counter
    for _ in range(1000):
        with lock:
            counter += 1

五、常用线程相关方法

方法作用
start()启动线程
join()等待线程结束
is_alive()判断线程是否存活
setDaemon()设置守护线程,主线程结束自动结束子线程

六、线程池(ThreadPoolExecutor)

Python 3.2+ 提供 concurrent.futures 模块,简化线程池管理:

from concurrent.futures import ThreadPoolExecutor
import time

def worker(num):
    print(f"线程 {num} 开始")
    time.sleep(1)
    return f"线程 {num} 结束"

with ThreadPoolExecutor(max_workers=3) as executor:
    futures = [executor.submit(worker, i) for i in range(5)]
    for future in futures:
        print(future.result())

七、多线程常见问题

  • GIL限制:Python解释器中全局解释器锁限制了多线程对多核CPU的利用率,适合I/O密集型任务,不适合CPU密集型任务。
  • 死锁:多个线程互相等待对方释放锁,导致程序卡死。需要合理设计锁机制,避免死锁。
  • 资源竞争:访问共享资源时需加锁,防止数据不一致。

八、实战场景建议

  • 网络爬虫、文件I/O、多任务等待等适合用多线程。
  • CPU密集型任务推荐使用多进程(multiprocessing模块)。
  • 结合线程池简化线程管理,提高代码可读性和效率。

好的!下面给你一个Python多线程爬虫的完整示例,演示如何用多线程并发请求多个网页,并收集结果。示例包含线程创建、同步、线程池使用等内容,适合实战参考。


Python多线程爬虫示例

import threading
import requests
from queue import Queue
from concurrent.futures import ThreadPoolExecutor

# 模拟的目标网址列表(示例用,可替换为真实网址)
urls = [
    "https://httpbin.org/get?query=1",
    "https://httpbin.org/get?query=2",
    "https://httpbin.org/get?query=3",
    "https://httpbin.org/get?query=4",
    "https://httpbin.org/get?query=5",
]

# 用于保存抓取结果的字典,线程安全用锁保护
results = {}
lock = threading.Lock()

def fetch_url(url):
    """请求指定URL,返回状态码和内容长度"""
    try:
        response = requests.get(url, timeout=5)
        content_length = len(response.content)
        with lock:
            results[url] = (response.status_code, content_length)
        print(f"[完成] {url} 状态码: {response.status_code}, 内容长度: {content_length}")
    except Exception as e:
        with lock:
            results[url] = (None, None)
        print(f"[错误] {url} 请求失败,原因:{e}")

def thread_pool_crawler(url_list):
    """使用线程池爬取URL列表"""
    max_workers = 3  # 最大线程数
    with ThreadPoolExecutor(max_workers=max_workers) as executor:
        executor.map(fetch_url, url_list)

if __name__ == "__main__":
    print("开始多线程爬虫任务...")
    thread_pool_crawler(urls)
    print("\n所有任务完成,结果汇总:")
    for url, (status, length) in results.items():
        print(f"{url} -> 状态码: {status}, 内容长度: {length}")

代码解析

  • fetch_url:具体爬取任务,发送请求并将结果写入共享字典,使用锁保证线程安全。
  • thread_pool_crawler:使用 ThreadPoolExecutor 创建线程池,自动管理线程创建与销毁,调用 fetch_url 并发爬取。
  • urls:待爬取的URL列表,可以替换为你实际目标。
  • 程序结束后,打印所有URL的请求结果。

运行环境准备

pip install requests

扩展建议

  • 添加异常处理和重试机制,保证请求稳定。
  • 加入请求头、代理池,避免被封禁。
  • 对爬取结果做存储,如写入文件或数据库。
  • 限制爬取频率,避免过载服务器。