文章目录
一、线程与多线程概念
1.1 线程与进程的区别
- 进程(Process): 是计算机中的一个程序运行实例,每个进程都有独立的内存空间。
- 线程(Thread): 是进程中的一个执行单元,一个进程可以包含多个线程,它们共享该进程的内存空间。
区别:
- 多进程适合CPU密集型任务,进程之间互不干扰,资源独立。
- 多线程适合IO密集型任务,线程之间共享数据,资源开销小。
1.2 Python中的多线程特点
- 全局解释器锁(GIL): Python的GIL限制了同一时间只有一个线程在运行,因此在CPU密集型任务中,多线程无法真正实现并行,而适合用于IO密集型任务。
- 线程模块: Python提供了
_thread
和threading
两个模块用于多线程编程。_thread
是底层模块,threading
是高级模块,使用更加简洁易用。
二、Python threading
模块常用方法
在Python中,使用threading
模块实现多线程编程。
2.1 创建线程
使用threading.Thread()
创建线程:
import threading
import time
def print_numbers():
for i in range(1, 6):
print(f"线程1:{i}")
time.sleep(1)
def print_letters():
for ch in "ABCDE":
print(f"线程2:{ch}")
time.sleep(1)
# 创建线程对象
t1 = threading.Thread(target=print_numbers)
t2 = threading.Thread(target=print_letters)
# 启动线程
t1.start()
t2.start()
# 等待线程执行完毕
t1.join()
t2.join()
print("主线程结束")
✅ 解释:
threading.Thread(target=...)
:创建线程并指定执行的函数。start()
:启动线程。join()
:阻塞主线程,等待子线程执行完成。
2.2 带参数的线程
使用args
或kwargs
向线程传递参数:
import threading
import time
def print_info(name, count):
for i in range(count):
print(f"{name} 第{i+1}次")
time.sleep(0.5)
# 创建线程并传递参数
t1 = threading.Thread(target=print_info, args=("线程1", 3))
t2 = threading.Thread(target=print_info, kwargs={"name": "线程2", "count": 5})
t1.start()
t2.start()
t1.join()
t2.join()
print("主线程结束")
✅ 解释:
args
:传递元组参数。kwargs
:传递字典参数。
2.3 线程ID和当前线程信息
获取线程ID和当前线程对象:
import threading
def show_thread_info():
print("当前线程:", threading.current_thread().name)
print("线程ID:", threading.get_ident())
t1 = threading.Thread(target=show_thread_info, name="MyThread-1")
t1.start()
t1.join()
✅ 解释:
threading.current_thread()
:返回当前线程对象。threading.get_ident()
:返回当前线程的唯一标识符。
三、线程同步与锁机制
由于多个线程共享同一块内存空间,多个线程同时访问和修改同一变量时可能会引发线程安全问题。为了解决这个问题,可以使用锁机制。
3.1 锁的使用
使用threading.Lock()
实现线程同步:
import threading
import time
# 共享变量
counter = 0
lock = threading.Lock()
def increase():
global counter
for _ in range(100000):
with lock: # 上锁
counter += 1
# 创建两个线程
t1 = threading.Thread(target=increase)
t2 = threading.Thread(target=increase)
t1.start()
t2.start()
t1.join()
t2.join()
print("最终计数器值:", counter)
✅ 解释:
lock = threading.Lock()
:创建锁对象。with lock:
:在操作共享资源时加锁,防止数据错乱。
3.2 可重入锁(RLock)
RLock
(可重入锁)允许同一线程多次获得同一把锁:
import threading
lock = threading.RLock()
def task():
print(f"{threading.current_thread().name} 尝试获取锁")
with lock:
print(f"{threading.current_thread().name} 第一次获取锁")
with lock:
print(f"{threading.current_thread().name} 第二次获取锁")
# 创建线程
t1 = threading.Thread(target=task, name="线程1")
t2 = threading.Thread(target=task, name="线程2")
t1.start()
t2.start()
t1.join()
t2.join()
✅ 解释:
threading.RLock()
:支持同一线程多次获取同一把锁,防止死锁。
四、线程池实现并发任务
Python3提供了concurrent.futures.ThreadPoolExecutor
来实现线程池,提高多线程编程效率。
4.1 使用线程池并发执行任务
from concurrent.futures import ThreadPoolExecutor
import time
def task(n):
print(f"线程 {n} 开始")
time.sleep(2)
return f"线程 {n} 完成"
# 使用线程池执行
with ThreadPoolExecutor(max_workers=4) as executor:
futures = [executor.submit(task, i) for i in range(1, 6)]
# 获取执行结果
for future in futures:
print(future.result())
✅ 解释:
ThreadPoolExecutor(max_workers=4)
:创建线程池,最多同时执行4个线程。executor.submit()
:向线程池提交任务。future.result()
:获取线程执行的返回结果。
五、使用Thread
子类创建线程
除了直接使用Thread
类,还可以通过继承Thread
类来创建自定义线程:
import threading
import time
class MyThread(threading.Thread):
def __init__(self, name, delay):
super().__init__()
self.name = name
self.delay = delay
def run(self):
for i in range(3):
print(f"{self.name} 执行第 {i+1} 次")
time.sleep(self.delay)
# 创建自定义线程
t1 = MyThread("线程1", 1)
t2 = MyThread("线程2", 2)
t1.start()
t2.start()
t1.join()
t2.join()
print("主线程结束")
✅ 解释:
- 自定义类
MyThread
继承自Thread
。 - 重写
run()
方法实现具体的线程逻辑。
六、总结
本文介绍了Python中多线程编程的基本知识,包括:
threading
模块的使用方法- 线程同步与锁机制
- 使用线程池提高并发效率
- 自定义线程类