好的!下面给你一份关于 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
扩展建议
- 添加异常处理和重试机制,保证请求稳定。
- 加入请求头、代理池,避免被封禁。
- 对爬取结果做存储,如写入文件或数据库。
- 限制爬取频率,避免过载服务器。
发表回复