基本说明
线程(Thread)是操作系统进行调度的最小单位,是进程中的一个独立执行单元。线程与进程相比,具有更轻量级、更高效率、更易调度、共享资源等优点。
在传统的单核CPU中,操作系统通过时间片轮转算法将CPU的时间片分配给多个线程,实现并发执行。在多核CPU的环境下,多个线程可以同时运行,提高了程序的并发性和性能。
线程可以共享进程中的内存和资源,因此可以用来实现并发编程和异步编程,提高程序的执行效率和响应速度。
在Python中,可以使用threading模块来创建和管理线程。可以通过继承Thread类或者传递一个函数对象来创建一个新线程。线程启动后,可以通过join()方法等待线程执行完成。可以使用锁、条件变量、信号量等同步机制来保证线程之间的同步和安全。
线程在Python中广泛应用于多任务并发处理、GUI编程、Web应用等场景,具有重要的作用和价值。
入门级别
1. 线程的创建
使用threading模块中的Thread类可以创建一个新的线程。创建线程时需要指定线程的目标函数,即线程要执行的代码,以及传递给目标函数的参数。
import threading
def target_function(arg1, arg2):
# 线程要执行的代码
pass
# 创建线程
thread = threading.Thread(target=target_function, args=(arg1, arg2))
2. 线程的启动和执行
创建线程之后,需要调用start()方法来启动线程,并开始执行线程的目标函数。
# 启动线程
thread.start()
# 等待线程执行完成
thread.join()
3. 线程的同步
线程在执行时会共享进程中的内存和资源,因此可能会出现竞争条件和并发访问问题。为了解决这些问题,Python提供了锁、条件变量、信号量等同步机制。
import threading
# 创建锁对象
lock = threading.Lock()
# 在代码中需要同步的位置使用锁来保证线程安全
with lock:
# 临界区代码
pass
中级级别
1. 线程池
线程池可以在程序启动时预先创建多个线程,然后将任务提交到线程池中执行。这样可以避免频繁创建和销毁线程,提高程序的性能。
import concurrent.futures
# 创建线程池
with concurrent.futures.ThreadPoolExecutor(max_workers=4) as executor:
# 提交任务到线程池中执行
future = executor.submit(target_function, arg1, arg2)
# 获取任务的执行结果
result = future.result()
2. 线程间通信
线程之间需要进行通信时,可以使用共享内存、队列等方式进行数据传递。
import queue
import threading
import time
# 创建队列对象
q = queue.Queue()
# 定义生产者线程函数
def producer():
# 生产者线程往队列中放入数据
for i in range(10):
data = f"生产者生产的数据:{i}"
q.put(data)
time.sleep(1)
# 定义消费者线程函数
def consumer():
# 消费者线程从队列中取出数据
while True:
if q.qsize() > 0:
data = q.get()
print(f"消费者消费了数据:{data}")
time.sleep(1)
else:
time.sleep(1)
# 创建生产者线程并启动
producer_thread = threading.Thread(target=producer)
producer_thread.start()
# 创建消费者线程并启动
consumer_thread = threading.Thread(target=consumer)
consumer_thread.start()
3. 线程的异常处理
线程在执行过程中可能会发生异常,需要对异常进行捕获和处理,避免程序崩溃。
import threading
def target_function():
try:
# 线程要执行的代码
pass
except Exception as e:
# 捕获异常并进行处理
print(f"线程执行发生异常:{e}")
# 创建线程并启动
thread = threading.Thread(target=target_function)
thread.start()
高级级别
通过condition实现生产者消费者
import threading
import time
# 缓冲区大小
BUFFER_SIZE = 10
# 生产者类
class Producer(threading.Thread):
def __init__(self, condition, buffer):
threading.Thread.__init__(self)
self.condition = condition
self.buffer = buffer
def run(self):
for i in range(20):
self.condition.acquire()
# 缓冲区已满,等待消费者消费
while len(self.buffer) == BUFFER_SIZE:
print('缓冲区已满,等待消费者消费')
self.condition.wait()
# 生产物品并添加到缓冲区
item = 'item %s' % i
self.buffer.append(item)
print('生产者生产 %s' % item)
# 通知消费者可以消费了
self.condition.notify()
self.condition.release()
time.sleep(1)
# 消费者类
class Consumer(threading.Thread):
def __init__(self, condition, buffer):
threading.Thread.__init__(self)
self.condition = condition
self.buffer = buffer
def run(self):
for i in range(20):
self.condition.acquire()
# 缓冲区为空,等待生产者生产
while len(self.buffer) == 0:
print('缓冲区为空,等待生产者生产')
self.condition.wait()
# 从缓冲区取出物品并消费
item = self.buffer.pop(0)
print('消费者消费 %s' % item)
# 通知生产者可以生产了
self.condition.notify()
self.condition.release()
time.sleep(1)
if __name__ == '__main__':
buffer = []
condition = threading.Condition()
producer = Producer(condition, buffer)
consumer = Consumer(condition, buffer)
producer.start()
consumer.start()
producer.join()
consumer.join()
上面的代码实现了一个生产者-消费者模型,其中生产者和消费者通过共享缓冲区进行通信。代码中使用了 Python 的 threading 模块中的 Condition 对象来同步生产者和消费者线程。
在程序运行时,首先创建了一个空缓冲区和一个 Condition 对象。生产者和消费者线程分别传入这个 Condition 对象和共享的缓冲区进行初始化。然后启动生产者和消费者线程,开始生产和消费物品。生产者线程每隔 1 秒生产一个物品并将其添加到缓冲区,如果缓冲区已满则等待消费者线程消费。消费者线程每隔 1 秒从缓冲区中取出一个物品进行消费,如果缓冲区为空则等待生产者线程生产。
在生产者和消费者线程进行生产和消费操作时,都需要首先获取 Condition 对象的锁,然后通过 Condition 对象的 wait 方法进入等待状态,直到其他线程通知它们可以继续执行。当一个线程生产或消费完毕后,通过 Condition 对象的 notify 方法通知其他线程可以继续执行,然后释放 Condition 对象的锁,让其他线程进入执行状态。
通过 Condition 对象的 wait、notify 和 release 方法,可以实现线程间的同步,保证生产者和消费者线程在共享缓冲区的操作时不会互相干扰,从而避免了竞态条件和死锁等问题。
import threading
import time
# 工作线程类
class Worker(threading.Thread):
def __init__(self, event):
threading.Thread.__init__(self)
self.event = event
def run(self):
print('工作线程 %s 等待事件' % self.name)
self.event.wait() # 等待事件
print('工作线程 %s 收到事件,开始工作' % self.name)
# 主线程
if __name__ == '__main__':
event = threading.Event()
threads = []
# 创建 5 个工作线程
for i in range(5):
t = Worker(event)
threads.append(t)
t.start()
# 主线程等待 3 秒后发送事件
print('主线程等待 3 秒后发送事件')
for i in range(3):
print(i+1)
time.sleep(1)
event.set() # 发送事件
# 等待所有工作线程完成
for t in threads:
t.join()
print('所有工作线程完成')
在上面的代码中,主线程创建了一个 Event 对象,并创建了 5 个工作线程并启动它们。工作线程通过调用 Event 对象的 wait 方法进入等待状态,等待主线程发送事件。主线程等待 3 秒后发送事件,通知工作线程可以开始工作。当一个工作线程收到事件后,通过打印一条消息表示开始工作。主线程等待所有工作线程完成后,打印一条消息表示所有工作线程都已完成。
通过 Event 对象的 wait 和 set 方法,可以实现多个线程之间的同步。wait 方法用于等待事件,如果事件未发生则一直阻塞线程,直到事件被其他线程发生为止。set 方法用于发送事件,通知其他等待线程可以继续执行。多个线程可以共享同一个 Event 对象,从而实现同步。