目录
需要导入threading库中Thread类,例如 from threading import Thread
两种方法实现多线程
1、类继承Thread父类,并重写init方法(初始化需要接收的一些属性),run方法(里面编写多线程的业务逻辑),例如:
class MyThread(Thread):
def __init__(self, num):
self.num = num
super().__init__()
def run(self):
count = self.num
while count:
print(f"{time.strftime('%H:%M:%S')} {threading.current_thread().name} 计数{count} ")
time.sleep(2)
count -= 1
2、不继承父类Thread,直接通过Thread类提供的初始化实例方法接收参数
def threading_task(num):
count = num
while count:
print(f"{time.strftime('%H:%M:%S')} {threading.current_thread().name} 计数{count} ")
time.sleep(2)
count -= 1
my_thread1 = threading.Thread(target=threading_task, args=(3,), name='my_thread1')
my_thread2 = threading.Thread(target=threading_task, args=(2,), name='my_thread2')
3、选择上面任意一种方式生成thread的实例,调用start方法启动多线程 thread.start()
比如用上面1的实现方法调试:
if __name__ == "__main__":
print(f"{time.strftime('%H:%M:%S')} 主进程开始")
my_thread1 = MyThread(3)
my_thread2 = MyThread(2)
my_thread1.name = 'my_thread1'
my_thread2.name = 'my_thread2'
my_thread1.start()
my_thread2.start()
my_thread1.join()
my_thread2.join()
print(f"{time.strftime('%H:%M:%S')} 主进程结束")
22:21:32 主进程开始
22:21:32 my_thread1 计数3
22:21:32 my_thread2 计数2
22:21:34 my_thread2 计数1 22:21:34 my_thread1 计数2
22:21:36 my_thread1 计数1
22:21:38 主进程结束
注意:join的用法跟多进程一样,可以参考:Python的多进程_fighter_狂奔的博客-CSDN博客
比如用上面2的实现方法调试:
if __name__=='__main__':
print(f"{time.strftime('%H:%M:%S')} 主进程开始")
my_thread1 = threading.Thread(target=threading_task, args=(3,), name='my_thread1')
my_thread2 = threading.Thread(target=threading_task, args=(2,), name='my_thread2')
my_thread1.start()
my_thread2.start()
my_thread1.join()
my_thread2.join()
print(f"{time.strftime('%H:%M:%S')} 主进程结束")
运行结果:
22:18:06 主进程开始
22:18:06 my_thread1 计数3
22:18:06 my_thread2 计数2
22:18:08 my_thread2 计数1 22:18:08 my_thread1 计数2
22:18:10 my_thread1 计数1
22:18:12 主进程结束
注意:daemon的用法跟多进程一样,可以参考:Python的多进程_fighter_狂奔的博客-CSDN博客
Lock
线程锁(Thread Lock)是一种多线程编程中的同步机制,用于确保多个线程不会同时访问共享资源,从而避免竞争条件和数据损坏。下面是一个使用线程锁的Python多线程示例:
import threading
# 共享资源
counter = 0
# 创建一个线程锁
lock = threading.Lock()
# 线程函数,用于增加共享资源的值
def increment():
global counter
# 获取线程锁
lock.acquire()
for i in range(100000):
counter += 1
# 释放线程锁
lock.release()
# 创建两个线程
thread1 = threading.Thread(target=increment)
thread2 = threading.Thread(target=increment)
thread3 = threading.Thread(target=increment)
# 启动线程
thread1.start()
thread2.start()
thread3.start()
# 等待线程完成
thread1.join()
thread2.join()
thread3.join()
# 打印最终的共享资源值
print("Final Counter:", counter)
Final Counter: 300000
Semaphore
Semaphore
是 Python 多线程编程中的同步原语之一,它是一个计数信号量,用于控制同时访问共享资源的线程数量。Semaphore
维护一个内部计数器,线程可以尝试获取信号量,如果计数器大于零,线程就能获取信号量,计数器减一;如果计数器为零,线程就需要等待,直到有其他线程释放信号量。
import threading
# 创建一个信号量,最大允许两个线程同时访问共享资源
import time
semaphore = threading.BoundedSemaphore(2)
# 共享资源
shared_resource = []
# 线程函数,用于访问共享资源
def access_shared_resource(thread_id):
with semaphore: # 尝试获取信号量
shared_resource.append(thread_id)
print(f"{time.strftime('%H:%M:%S')}")
print(f"Thread {thread_id} accessed the shared resource")
print(f"Shared Resource: {shared_resource}")
time.sleep(2)
# 创建多个线程
threads = []
for i in range(5):
thread = threading.Thread(target=access_shared_resource, args=(i,))
threads.append(thread)
# 启动线程
for thread in threads:
thread.start()
# 等待线程完成
for thread in threads:
thread.join()
print("All threads have finished")
调试结果:
22:57:50
Thread 0 accessed the shared resource
Shared Resource: [0]
22:57:50
Thread 1 accessed the shared resource
Shared Resource: [0, 1]
22:57:5222:57:52
Thread 3 accessed the shared resource
Thread 2 accessed the shared resource
Shared Resource: [0, 1, 3, 2]
Shared Resource: [0, 1, 3, 2]
22:57:54
Thread 4 accessed the shared resource
Shared Resource: [0, 1, 3, 2, 4]
All threads have finished
Process finished with exit code 0
Condition
Condition
是 Python 用于协调多个线程之间的操作顺序。Condition
允许线程等待某个条件成立,然后通知其他线程,以便它们可以执行相应的操作。
condition = threading.Condition() 两个线程同时使用这个对象用于控制两个线程的消息交互
condition.acquire() 获取锁,准备运行
condition.wait() 释放锁,阻塞中等待唤醒
condition.notify() 唤醒阻塞中的线程去运行
condition.release() 线程执行完成释放资源
import threading
# 共享资源
import time
shared_resource = []
condition = threading.Condition()
# 生产者线程函数,向共享资源中添加数据
def producer():
for i in range(1, 6):
with condition:
shared_resource.append(i)
print(f"{time.strftime('%H:%M:%S')} 生产: {i}")
condition.notify() # 通知消费者线程
print(f"{time.strftime('%H:%M:%S')} 通知消费者")
condition.wait() # 等待消费者线程通知
time.sleep(1)
# 消费者线程函数,从共享资源中取出数据
def consumer():
for _ in range(5):
with condition:
while not shared_resource:
print(f"{time.strftime('%H:%M:%S')} 产品不足,通知生产者")
condition.wait() # 等待生产者线程通知
data = shared_resource.pop(0)
print(f"{time.strftime('%H:%M:%S')} 消费: {data}")
condition.notify() # 通知生产者线程
time.sleep(1)
# 创建生产者和消费者线程
producer_thread = threading.Thread(target=producer)
consumer_thread = threading.Thread(target=consumer)
# 启动线程
producer_thread.start()
consumer_thread.start()
# 等待线程完成
producer_thread.join()
consumer_thread.join()
print("All threads have finished")
10:42:43 生产: 1
10:42:43 通知消费者
10:42:43 消费: 1
10:42:45 生产: 2
10:42:45 通知消费者
10:42:45 消费: 2
10:42:46 产品不足,通知生产者
10:42:46 生产: 3
10:42:46 通知消费者
10:42:46 消费: 3
10:42:47 生产: 4
10:42:47 通知消费者
10:42:47 消费: 4
10:42:48 产品不足,通知生产者
10:42:48 生产: 5
10:42:48 通知消费者
10:42:48 消费: 5
All threads have finished
Event(wait、set、clear)
wait方法,线程被阻塞,等待唤醒,wait加参数,表示最多等待多少秒,不加参数表示一直等待
set方法,设置标志位True,wait中的线程被唤醒并执行
clear方法,设置标志位False
import threading
# 共享资源
import time
shared_resource = []
event = threading.Event()
# 生产者线程函数,向共享资源中添加数据
def producer():
for i in range(1, 6):
shared_resource.append(i)
print(f"{time.strftime('%H:%M:%S')} 生产: {i} ")
event.set() # 通知消费者线程
print(f"{time.strftime('%H:%M:%S')} 通知消费者 ")
event.wait() # 等待消费者线程通知
time.sleep(1)
# 消费者线程函数,从共享资源中取出数据
def consumer():
for _ in range(5):
while not shared_resource:
print(f"{time.strftime('%H:%M:%S')} 产品不足,通知生产者 ")
event.wait() # 等待生产者线程通知
data = shared_resource.pop(0)
print(f"{time.strftime('%H:%M:%S')} 消费: {data} ")
event.set() # 通知生产者线程
time.sleep(1)
# 创建生产者和消费者线程
producer_thread = threading.Thread(target=producer)
consumer_thread = threading.Thread(target=consumer)
# 启动线程
producer_thread.start()
consumer_thread.start()
# 等待线程完成
producer_thread.join()
consumer_thread.join()
print("All threads have finished")
运行结果如下:
10:59:35 生产: 1
10:59:35 通知消费者
10:59:35 消费: 1
10:59:36 产品不足,通知生产者 10:59:36 生产: 2
10:59:36 通知消费者
10:59:36 消费: 2
10:59:37 生产: 3
10:59:37 通知消费者
10:59:37 消费: 3
10:59:38 生产: 4 10:59:38 消费: 4
10:59:38 通知消费者
10:59:39 生产: 5 10:59:39 消费: 5
10:59:39 通知消费者
All threads have finished
Queue
Queue
(队列)是 Python 多线程编程中用于线程间通信的重要数据结构。它提供了一种线程安全的方式来在多个线程之间传递数据。Python提供了 queue
模块,其中包含了多种队列类型,包括 Queue(先进先出)
、LifoQueue(后进先出)
和 PriorityQueue(优先级队列)
。最常见的用法是 Queue
。
# 定义一个共享缓存队列,用于两个线程的数据存放和读取 q = queue.Queue(maxsize=5) 当队列存满了后生产者就不在生产数据,需等消费者消费后再生产
import queue
import threading
import time
# 定义一个共享缓存队列,用于两个线程的数据存放和读取
q = queue.Queue(maxsize=5)
def product():
count = 1
while True:
print(f"{time.strftime('%H:%M:%S')} 生产 item{count}")
q.put(f'item{count}')
count += 1
time.sleep(1)
print(f"当前产品数:{q.qsize()}")
def customer():
while True:
print(f"{time.strftime('%H:%M:%S')} 消费 {q.get()}")
time.sleep(5)
t0 = threading.Thread(target=product)
t1 = threading.Thread(target=customer)
t0.start()
t1.start()
t0.join()
t1.join()
调试结果:
11:23:40 生产 item1
11:23:40 消费 item1
当前产品数:0
11:23:41 生产 item2
当前产品数:1
11:23:42 生产 item3
当前产品数:2
11:23:43 生产 item4
当前产品数:3
11:23:44 生产 item5
11:23:45 消费 item2
当前产品数:3
11:23:45 生产 item6
当前产品数:4
11:23:46 生产 item7
当前产品数:5
11:23:47 生产 item8
11:23:50 消费 item3
当前产品数:5
11:23:51 生产 item9
11:23:55 消费 item4
当前产品数:5
...
...
Pool
面向对象编程中,创建和销毁对象是很浪费时间的,对于频繁的需要创建和销毁的线程的业务中可以使用线程池来处理,线程池中会默认初始化一定数量的线程对象,有任务来时就分配一个空闲线程去处理,如果线程池无空闲就新建一个线程去处理业务。
from multiprocessing.pool import ThreadPool
import threading
import time
# 创建一个线程锁, 使用线程锁来确保输出的有序性,避免输出内容交织在一起
output_lock = threading.Lock()
# 定义一个函数,用于在线程池中并行执行
def square(x):
with output_lock:
print(f"{time.strftime('%H:%M:%S')} {x}*{x}={x * x} ")
time.sleep(2)
if __name__ == '__main__':
# 创建一个线程池,设置线程数为4(可以根据需要调整)
pool = ThreadPool(4)
for i in range(1, 10):
pool.apply_async(func=square, args=(i,))
pool.close()
pool.join()
调试结果展示,每次有4个线程同时运行
12:00:12 1*1=1
12:00:12 2*2=4
12:00:12 3*3=9
12:00:12 4*4=16
12:00:14 5*5=25
12:00:14 6*6=36
12:00:14 7*7=49
12:00:14 8*8=64
12:00:16 9*9=81