Python使用 - 多线程
常见术语及用法
基本使用
# 定义线程类 class MyThread(threading.Thread): def __init__(self): super(MyThread, self).__init__() # 或 threading.Thread.__init__(self) def run(self) -> None: tid = threading.currentThread().ident tname = threading.currentThread().getName() print("===== 线程开始: id: %d, name: %s" % (tid, tname)) # 线程休眠 time.sleep(5) print("===== 线程结束: id: %d, name: %s" % (tid, tname)) print("主线程: id: %d, name: %s" % (threading.currentThread().ident, threading.currentThread().name)) # 创建线程 thread1 = MyThread() # 启动线程 thread1.start() # 主线程等待thread1线程结束 thread1.join() print("主线程退出")
线程同步:锁
多个人从苹果箱子里取苹果吃,一次只能取一个
import threading import time class AppleBox: def __init__(self, apple_num: int): self.apple_num = apple_num self.res_lock = threading.Lock() def get(self): self.res_lock.acquire() t_apple_no = -1 if self.apple_num > 0: t_apple_no = self.apple_num self.apple_num -= 1 self.res_lock.release() return t_apple_no class MyThread(threading.Thread): def __init__(self, apple_box: AppleBox): super(MyThread, self).__init__() # 或 threading.Thread.__init__(self) self.apple_box = apple_box def run(self) -> None: tid = threading.currentThread().ident tname = threading.currentThread().getName() for i in range(20): # print("===== %s(%d) 尝试从箱子里拿苹果\n" % (tname, tid)) apple_no = self.apple_box.get() if apple_no < 0: print("===== %s(%d) 苹果拿完了\n" % (tname, tid)) return print("===== %s(%d) 拿到了%s号苹果, 走到边上开始吃苹果\n" % (tname, tid, apple_no)) time.sleep(3) # print("===== %s(%d) 吃完%s号苹果\n" % (tname, tid, apple_no)) apple_box = AppleBox(15) thread_list = [] for i in range(5): # 创建线程 thread1 = MyThread(apple_box) # 启动线程 thread1.start() thread_list.append(thread1) # 主线程等待上面的线程执行完毕 for t in thread_list: t.join() print("退出主线程")
线程同步:锁+线程间通信
上面吃苹果的例子情况比较简单,访问共享资源的条件是:有人在访问的话就等待;
现在访问共享资源的条件增加了,1、有人在访问的话要等,2、如果资源是空或满的的要等;
仅仅用锁的方式:
# 共享资源 class Products: def __init__(self, max_num: int): self.num = 0 self.producing_num = 0 self.max_num = max_num self.res_lock = threading.Lock() self.cond_empty = threading.Condition(self.res_lock) # 产品被消耗完时, 消费者等待 self.cond_full = threading.Condition(self.res_lock) # 库存满时, 生产者等待 def take(self): tid = threading.currentThread().ident tname = threading.currentThread().getName() self.res_lock.acquire() # self.cond_empty.acquire() while self.num <= 0: print("%s: 没有产品, 等待3s" % (tname)) self.res_lock.release() time.sleep(3) self.res_lock.acquire() print("%s: 3s到了, 检查是否有产品" % (tname)) self.num -= 1 print("%s: 消耗了1个产品,当前总共%s" % (tname, self.num)) self.res_lock.release() # self.cond_empty.release() # 模拟消耗耗时, 物品是立即拿走的, 然后到边上去消耗, 而不是在仓库里消耗 time.sleep(10 + random.random()) def put(self): tid = threading.currentThread().ident tname = threading.currentThread().getName() self.res_lock.acquire() while (self.num + self.producing_num) >= self.max_num: print("%s: 库存满了, 等待3s, %s个生产中" % (tname, self.producing_num)) self.res_lock.release() time.sleep(3) self.res_lock.acquire() print("%s: 3s到了, 检查库存是否满" % (tname)) self.producing_num += 1 self.res_lock.release() # 模拟生产耗时, 要生产出来了物品数量才能+1 time.sleep(5 + random.random()) self.res_lock.acquire() self.producing_num -= 1 self.num += 1 print("%s: 生产了1个产品,当前总共%s" % (tname, self.num)) self.res_lock.release()
也可以做,但是效率会相对较低,因为需要不断的去轮询检查是不是空或者满了。
用线程间通信的方式
# 共享资源 class Products: def __init__(self, max_num: int): self.num = 0 self.producing_num = 0 self.max_num = max_num self.res_lock = threading.Lock() self.cond_empty = threading.Condition(self.res_lock) # 产品被消耗完时, 消费者等待 self.cond_full = threading.Condition(self.res_lock) # 库存满时, 生产者等待 def take(self): tid = threading.currentThread().ident tname = threading.currentThread().getName() self.res_lock.acquire() # self.cond_empty.acquire() while self.num <= 0: print("%s: 没有产品, 等待" % (tname)) self.cond_empty.wait() print("%s: 消费者被唤醒,检查是否有产品" % (tname)) self.num -= 1 print("%s: 消耗1个产品,当前总共%s,通知生产者" % (tname, self.num)) # 产品被消耗了, 腾出了库存空间, 通知生产者 self.cond_full.notify_all() self.res_lock.release() # self.cond_empty.release() # 模拟消耗耗时, 物品是立即拿走的, 然后到边上去消耗, 而不是在仓库里消耗 time.sleep(10 + random.random())
def put(self): tid = threading.currentThread().ident tname = threading.currentThread().getName() self.res_lock.acquire() while (self.num + self.producing_num) >= self.max_num: print("%s: 库存满了, 等待, %s个生产中" % (tname, self.producing_num)) self.cond_full.wait() print("%s: 生产者被唤醒,检查库存是否满" % (tname)) self.producing_num += 1 self.res_lock.release() # 模拟生产耗时, 要生产出来了物品数量才能+1 time.sleep(5 + random.random()) self.res_lock.acquire() self.producing_num -= 1 self.num += 1 print("%s: 生产了1个产品,当前总共%s,通知消费者" % (tname, self.num)) # 有产品了, 通知消费者 self.cond_empty.notify_all() self.res_lock.release()
生产者,消费者
class Producer(threading.Thread): def __init__(self, products): super(Producer, self).__init__() # 或 threading.Thread.__init__(self) self.products = products def run(self) -> None: for i in range(10): self.products.put() class Consumer(threading.Thread): def __init__(self, products): super(Consumer, self).__init__() self.products = products def run(self) -> None: for i in range(10): self.products.take() products = Products(5) producer1 = Producer(products) producer2 = Producer(products) producer1.start() producer2.start() consumer1 = Consumer(products) consumer2 = Consumer(products) consumer1.start() consumer2.start() producer1.join() producer2.join() consumer1.join() consumer2.join() print("退出主线程")
java中有,Python中还没看到的:
守护线程
线程池
Priority线程优先级
参考
Java并发编程基础:线程与同步 - 知乎 (zhihu.com)
走进并发,线程同步与线程通信全解析 - 知乎 (zhihu.com)
Java 生产者和消费者3种实现方式_用java实现生产者消费者_小博要变强啊~的博客-CSDN博客
分类:
Python
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下