[Python学习日记-88] 并发编程之多进程 —— 队列与生产者消费者模型
[Python学习日记-88] 并发编程之多进程 —— 队列与生产者消费者模型
简介
队列
一、队列的介绍
二、队列的使用
生产者消费者模型
一、为什么要使用生产者消费者模型
二、什么是生产者消费者模型
三、生产者消费者模型的优势
四、生产者消费者模型的实现
JoinableQueue
管道(不推荐)
简介
在多进程编程当中允许程序创建多个进程,每个进程拥有独立的地址空间、内存、数据栈等资源,能够并行执行,互不干扰。在一个程序或系统中通常会让多个进程协同工作,那就会发生数据交换和信息共享,此时就需要一种有效的进程间通信(Inter - Process Communication, IPC)机制,而队列就是其中一种。本篇将会介绍队列的使用和生产者消费者模型。
队列
一、队列的介绍
mutiprocessing 模块支持使用消息传递的队列来实现进程间通信,可以使用 Queue 类,其语法如下:
Queue([maxsize]) # 创建共享的进程队列
该类提供了一个进程安全的队列,可用于在不同进程之间传递数据。它的底层通过管道和锁定机制实现,确保了多进程环境下数据传递的准确性与安全性。
类的参数介绍:
- maxsize:该参数用来限制队列中允许的最大项数,省略该参数则表示无大小限制
注意:对于该参数有两点需要明确
1、队列中适合存放精简的小数据,即消息,而非大数据
2、队列实际上占用的是内存空间,即便 maxsize 无大小限制也受限于系统内存大小
队列的基本操作方法:
- put(obj, blocked=True, timeout=None):该方法将数据 obj 放入队列中。若 blocked 为 True(默认值)且 timeout 为正值,当队列已满时,该方法会阻塞 timeout 指定的时间,直至队列有剩余空间;若超时,将抛出 Queue.Full 异常。若 blocked 为 False,且队列已满,会立即抛出 Queue.Full 异常
- get(blocked=True, timeout=None):该方法可以从队列读取并删除一个元素。当 blocked 为 True(默认值)且 timeout 为正值时,若在等待时间内未取到任何元素,会抛出 Queue.Empty 异常。若 blocked 为 False,若队列有可用值则立即返回,否则,若队列为空,会立即抛出 Queue.Empty 异常
- put_nowait():与 put(obj, blocked=False) 效果相同
- get_nowait():与 get(blocked=False) 效果相同
- qsize():返回队列中当前元素的数量。由于多进程环境的复杂性,该结果可能不可靠,例如在获取数量的瞬间,其他进程可能已对队列进行了修改
- empty():判断队列是否为空。该结果也可能不可靠,因为在返回 True 的过程中,队列可能又加入了项目
- full():判断队列是否已满。该结果也可能存在不可靠性
其他方法:
- cancel_join_thread():不会在进程退出时自动连接后台线程。可以防止 join_thread() 阻塞
- close():关闭队列,防止队列中加入更多数据。调用此方法,后台线程将继续写入那些已经入队列但尚未写入的数据,但将在此方法完成时马上关闭。如果队列被垃圾回收机制回收,将调用此方法。关闭队列不会在队列使用者中产生任何类型的数据结束信号或异常,也就是说使用者在使用 get() 被阻塞,并不会因为队列关闭而收到结束信号或异常
- join_thread():连接队列的后台线程。此方法用于在调用 close() 之后,等待所有队列项被消耗。通常使用队列的创建人,及你,不会去调用该方法,可以通过调用 cancel_join_thread() 来防止调用
二、队列的使用
指定队列大小:
from multiprocessing import Queueq = Queue(3) # 队列长度设置为3q.put('hello')
q.put({'a':1})
q.put([3,3,3])
print("队列是否满了:",q.full())# q.put(4) # 当队列满了的时候再放数据进去就会卡住,直到有人取数据print("第一次取:",q.get())
print("第二次取:",q.get())
print("第三次取:",q.get())
print("队列是否空了:",q.empty())print("第四次取:",q.get()) # 当队列是空的时候也会卡住,直到有人放数据进来
输出结果:
当队列满时再放数据进去就会卡住,知道有人取数据(不注释 q.put(4) 时)
当按照队列长度输入得刚刚好时(注释 q.put(4) 时)
不指定队列大小:
from multiprocessing import Queueq = Queue() # 不指定大小可以无限往里放,但限制于你的实际内存大小q.put('hello')
q.put({'a':1})
q.put([3,3,3])
print("队列是否满了:",q.full())print("第一次取:",q.get())
print("第二次取:",q.get())
print("第三次取:",q.get())
print("队列是否空了:",q.empty())
输出结果:
生产者消费者模型
一、为什么要使用生产者消费者模型
生产者指的是生产数据的任务,消费者指的是处理数据的任务,在并发编程中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据。同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者。为了解决这个问题于是引入了生产者消费者模型。
二、什么是生产者消费者模型
生产者消费者模型是一种经典的设计模式,它巧妙的通过一个容器解决了生产者和消费者的强耦合问题。在该模型中,生产者和消费者彼此之间不直接通讯,而通过缓冲区(通常是一个队列)来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接放入缓冲区即可继续生产,而消费者不需要直接找到生产者拿数据,而试直接从缓冲区里取,这样生产者和消费者可以以不同的速度运行,极大地提高了系统的整体效率和灵活性。
三、生产者消费者模型的优势
- 解耦:生产者和消费者无需直接交互,它们仅与队列进行数据传递,从而显著降低了模块之间的耦合度。这意味着在系统的后续维护和扩展过程中,对生产者或消费者模块的修改不会对另一方产生直接影响,提高了系统的可维护性
- 提高效率:生产者和消费者能够并行工作,充分利用系统资源。例如,在一个数据处理系统中,生产者可以持续不断地从数据源获取数据并放入队列,而消费者则可以同时对队列中的数据进行处理,避免了因一方等待另一方而造成的资源浪费,提高了整体吞吐量
- 缓冲:队列作为缓冲区,能够有效平衡生产者和消费者的速度差异。当生产者生成数据的速度快于消费者处理数据的速度时,队列可以暂时存储多余的数据,防止数据丢失;反之,当消费者处理数据的速度快于生产者生成数据的速度时,队列中的数据可以保证消费者不会因等待数据而空闲,维持系统的稳定运行
四、生产者消费者模型的实现
我们以一个包子店为例,那么这个包子店的生产者消费者模型分析如下:
程序中有两类角色:
1、负责生产数据(生产者)
2、负责处理数据(消费者)
引入生产者消费者模型为了解决的问题是:让生产者和消费者进行解耦,平衡生产者与消费者之间的工作能力,从而提高程序整体处理数据的速度
实现模型:生产者 <——> 队列 <——> 消费者
基于队列实现生产者消费者模型:
from multiprocessing import Process,Queue
import timedef producer(name,q,product):for i in range(3):res = '%s%s' % (product,i)time.sleep(0.5)print('生产者%s生产了%s' % (name,res))q.put(res)def consumer(name,q):while True:res = q.get()if res is None:breaktime.sleep(1)print('消费者%s吃了%s' % (name,res))if __name__ == '__main__':# 容器q = Queue()# 生产者们p1 = Process(target=producer,args=('马国明',q,'叉烧包'))p2 = Process(target=producer,args=('刘德华',q,'生肉包'))p3 = Process(target=producer,args=('黎明',q,'豆沙包'))# 消费者们c1 = Process(target=consumer,args=('陆小凤',q))c2 = Process(target=consumer,args=('AngleBaby',q,))p1.start()p2.start()p3.start()c1.start()c2.start()p1.join()p2.join()p3.join()q.put(None) # 有多少个消费者就需要多少个q.put(None)print('主')
输出结果:
在代码中 q.put(None) 的作用是解决主进程永远不会结束的问题,这一问题的原因是生产者在生产完后就结束了,但是消费者在取空了队列 q 之后,则一直处于死循环中并卡在 q.get() 这一步,那我们只需要在生产者生产完毕后往队列中再发一个结束信号 None,然后消费者接收到结束信号 None 时就可以 break 跳出死循环。
有的小伙伴可能就会问了,在什么时候 q.put(None) 才合适呢?我们有几个选择:一是,在 producer() 中的循环结束后加;二是,在主进程当中加。最终我们选择的是在主进程当中加,这是因为生产者肯定不止一个,消费者也不会只有一个,这个时候如果是前者的情况下,有的生产者速度快提前结束了生产任务,那么就会在队列当中直接放入结束信号 None,那么某一个消费者取队列中的数据时就会取到结束信号 None,但是这个消费者还想继续吃包子啊,那么就会造成一个 bug,在消费者还没吃饱的时候就把人家赶走了,而后者则在 join() 后才加入结束信号 None,及确保了生产者的进程结束了,也不会有某一个消费者在吃包子的过程中突然就取到了结束信号 None。
其实我们的思路无非是发送结束信号而已,但是目前这种加结束信号的方式是不太高级的,我们可以使用另外一种队列(JoinableQueue),其提供了这种机制。
JoinableQueue
JoinableQueue 是 multiprocessing.Queue 的子类,它在普通队列的基础上提供了额外的功能,用于更精细地管理任务的完成情况。与普通队列不同,JoinableQueue 允许消费者通知生产者队列中的数据已经被成功处理,而通知进程是使用共享的信号和条件变量来实现的,其语法如下:
JoinableQueue([maxsize])
参数介绍:
- maxsize:该参数用来限制队列中允许的最大项数,省略该参数则表示无大小限制
方法介绍:
JoinableQueue 除了与 Queue 相同的方法外还具有以下方法
- task_done():消费者使用此方法发出信号,表示 get() 的返回数据已经被处理。如果调用此方法的次数大于从队列中数据的数量,将抛出 ValueError 异常
- join():生产者调用此方法进行阻塞,直到队列中所有的数据均被处理。阻塞将持续到队列中的每个数据均调用 task_done() 方法为止
对上面实现的生产者消费者模型进行改造:
from multiprocessing import Process,JoinableQueue
import timedef producer(name,q,product):for i in range(3):res = '%s%s' % (product,i)time.sleep(0.5)print('生产者%s生产了%s' % (name,res))q.put(res)q.join() # 会等待队列中的所有项目都返回 task_done()def consumer(name,q):while True:res = q.get()if res is None:breaktime.sleep(1)print('消费者%s吃了%s' % (name,res))q.task_done() # 该项目处理完成后向生产者发送通知if __name__ == '__main__':# 容器q = JoinableQueue()# 生产者们p1 = Process(target=producer,args=('马国明',q,'叉烧包'))p2 = Process(target=producer,args=('刘德华',q,'生肉包'))p3 = Process(target=producer,args=('黎明',q,'豆沙包'))# 消费者们c1 = Process(target=consumer,args=('陆小凤',q))c2 = Process(target=consumer,args=('AngleBaby',q,))# 把消费者们设置为守护进程c1.daemon = Truec2.daemon = Truep1.start()p2.start()p3.start()c1.start()c2.start()p1.join()p2.join()p3.join()print('主')
输出结果:
在代码中不同进程之间的等待关系如下
主进程 —— 等待(p1.join()、p2.join()、p3.join())——> p1、p2、p3 —— 等待(q.join())——> c1、c2
由于 q.join() 的存在,p1、p2、p3 结束了就证明 c1、c2 肯定都把队列中的数据处理完了,那么 c1、c2 也没有存在的价值了,它们应该随着主进程的结束而结束,所以把 c1、c2 设置成守护进程。
管道(不推荐)
mutiprocessing 模块实现进程间通信的第二种形式就是使用消息传递的管道,但并部推荐使用,因为。。。。管道的语法如下:
Pipe([duplex])
该类会在进程之间创建一条管道,并返回元组 (conn1,conn2),其中 conn1 和 conn2 分别表示管道两端的连接对象,需要注意的是管道的产生必须在产生 Process 对象之前。
类参数的介绍:
- duplex:默认管道是全双工的,如果将 duplex 设成 False,conn1 只能用于接收,conn2 只能用于发送
主要方法:
- conn1.recv():接收 conn2.send(obj) 发送的对象。如果没有消息可接收,recv() 会一直阻塞;如果连接的另外一端已经关闭,那么 recv() 方法会抛出 EOFError 异常
- conn1.send(obj):通过连接发送对象。obj 是与序列化兼容的任意对象
其他方法:
- conn1.close():关闭连接,如果 conn1 被垃圾回收机制回收,将自动调用此方法
- conn1.fileno():返回连接使用的整数文件描述符
- conn1.poll([timeout]):如果连接上的数据可用,返回 True。timeout 指定等待的最长时限。如果省略此参数,方法将立即返回结果;如果将 timeout 射成 None,操作将无限期地等待数据到达
- conn1.recv_bytes([maxlength]):接收 conn2.send_bytes() 方法发送的一条完整的字节消息。maxlength 指定要接收的最大字节数。如果进入的消息,超过了这个最大值,将抛出 IOError 异常,并且在连接上无法进行进一步读取;如果连接的另外一端已经关闭,再也不存在任何数据,将抛出 EOFError 异常
- conn2.send_bytes(buffer [, offset [, size]]):通过连接发送字节数据缓冲区,buffer 是支持缓冲区接口的任意对象,offset 是缓冲区中的字节偏移量,而 size 是要发送字节数。结果数据以单条消息的形式发出,然后调用 conn1.recv_bytes() 函数进行接收
- conn1.recv_bytes_into(buffer [, offset]):接收一条完整的字节消息,并把它保存在 buffer 对象中,该对象支持可写入的缓冲区接口(即 bytearray 对象或类似的对象);offset 指定缓冲区中放置消息处的字节位移。返回值是收到的字节数。如果消息长度大于可用的缓冲区空间,将引发 BufferTooShort 异常
基于管道实现生产者消费者模型:与队列的方式是类似的,因为队列就是管道加锁实现的
from multiprocessing import Process, Pipe
import time# 管道的流向是从左到右的,放入时关闭右侧,获取时关闭左侧
def consumer(p, name):left, right = pleft.close() # 接收方关闭左侧,从右侧取出while True:try:baozi = right.recv() # 如果包子还没放入则会进行等待print('%s 收到包子:%s' % (name, baozi))except EOFError:right.close()breakdef producer(seq, p, name):left, right = pright.close() # 发送方关闭右侧,从左侧放入for i in seq:left.send(i)print('%s 放入包子:%s' % (name, i))time.sleep(1)else:left.close()if __name__ == '__main__':# 创建管道left, right = Pipe()# 消费者c1 = Process(target=consumer, args=((left, right), 'c1'))c1.start()# 生产者seq = (i for i in range(10))producer(seq, (left, right), 'p1')# 执行完毕关闭隧道right.close()left.close()c1.join()print('主进程')
输出结果:
注意:生产者和消费者都没有使用管道的某个端点,就应该将其关闭,如在生产者中关闭管道的右端,在消费者中关闭管道的左端。如果忘记执行这些步骤,程序可能再消费者中的 recv() 操作上挂起。管道是由操作系统进行引用计数的,必须在所有进程中关闭管道后才能生产 EOFError 异常。因此在生产者中关闭管道不会有任何效果,付费消费者中也关闭了相同的管道端点
管道也可以用于双向通信,把客户端的请求视为管道的左侧,服务器的响应视为右侧,即请求与响应模型或远程过程调用,就可以使用管道编写与进程交互的程序。
相关文章:
[Python学习日记-88] 并发编程之多进程 —— 队列与生产者消费者模型
[Python学习日记-88] 并发编程之多进程 —— 队列与生产者消费者模型 简介 队列 一、队列的介绍 二、队列的使用 生产者消费者模型 一、为什么要使用生产者消费者模型 二、什么是生产者消费者模型 三、生产者消费者模型的优势 四、生产者消费者模型的实现 JoinableQ…...
Vue学习笔记集--computed
computed 在 Vue 3 的 Composition API 中,computed 用于定义响应式计算属性 它的核心特性是自动追踪依赖、缓存计算结果(依赖未变化时不会重新计算) 基本用法 1. 定义只读计算属性 import { ref, computed } from vue;const count ref(…...
python之多线程,多进程理解
目录 一,什么是多线程多进程 1,1 多线程 1.2 多进程 二,多线程 2.1 使用threading模块 三,多进程 3.1 使用multiprocessing模块 3.2 多进程的优势 3.3 进程间的通信 四,如何选择多进程还是多线程 五,异步编程的替代方案(协程) 在开发过程中,提升程序的并…...
3月29日星期六今日早报简报微语报早读
3月29日星期六,农历三月初一,早报#微语早读。 1、全国公立医疗机构自3月31日起全面停止收取门诊预交金; 2、永辉超市“胖东来调改店”已达47家店 一线员工薪酬涨幅50%以上; 3、两孩家庭补10万,三孩家庭补20万&#…...
栈:隐匿于计算机科学长卷的璀璨明珠
目录 🚀前言🌟栈的概念🤔栈的两种实现形式💯数组栈实现💯链表栈实现 ⚙️数组栈与链表栈对比🐧递归与栈💻总结 🚀前言 大家好!我是 EnigmaCoder。 在计算机科学的宏大版图…...
【万字总结】前端全方位性能优化指南(七)——按需加载、虚拟列表、状态管理
现代框架高阶优化——突破复杂场景的性能临界点 当Web应用进入「十万级组件、百万级数据」的复杂场景时,传统优化手段开始触及框架底层瓶颈:Redux的单一Store引发级联渲染风暴、全量加载的首屏资源阻塞关键交互、长列表滚动导致内存飙升直至页面崩溃……这些痛点正在倒逼框架…...
合并石子 | 第十四届蓝桥杯省赛JavaB组
在桌面从左至右横向摆放着 N 堆石子。 每一堆石子都有着相同的颜色,颜色可能是颜色 0,颜色 1 或者颜色 2 中的其中一种。 现在要对石子进行合并,规定每次只能选择位置相邻并且颜色相同的两堆石子进行合并。 合并后新堆的相对位置保持不变&…...
【商城实战(94)】构建高并发的负载均衡与集群架构
【商城实战】专栏重磅来袭!这是一份专为开发者与电商从业者打造的超详细指南。从项目基础搭建,运用 uniapp、Element Plus、SpringBoot 搭建商城框架,到用户、商品、订单等核心模块开发,再到性能优化、安全加固、多端适配…...
鸿蒙开发:了解Canvas绘制
前言 本文基于Api13 系统的组件无法满足我们的需求,这种情况下就不得不自己自定义组件,除了自定义组合组件,拓展组件,还有一种方式,那就是完全的自绘制组件,这种情况,常见的场景有,比…...
Ubuntu和Windows实现文件互传
1.开启Ubuntu下的FTP服务: (1)终端输入: sudo apt-get install vsftpd(2)安装完成后: 终端输入: /etc 是 Linux 系统的全局配置文件目录,存储系统和应用程序的配置信息…...
dav_pg8_vacuum
一、VACUUM基础概念 1.1 VACUUM的作用 在PostgreSQL中,当数据被更新或删除时,系统并不会立即释放物理空间,而是将其标记为 “可重用”。 随着时间推移,表中的死元组(已删除或已被新版本覆盖的数据)会越来越…...
革新汽车安全通信技术,美格智能全系车载通信模组支持NG-eCall
根据QYR(恒州博智)的统计及预测,2024年全球汽车无线紧急呼叫(eCall)设备市场销售额达到了25.17亿美元,预计2031年将达到44.97亿美元,年复合增长率(CAGR 2025-2031)为8.8%…...
Ubuntu桌面环境下网络设置选项缺失问题解决
一、问题现象 在Ubuntu桌面环境中,网络设置界面中仅显示VPN设置,未显示常规网络配置选项,导致无法通过图形界面修改网络配置。但通过命令行工具可正常设置网络。 二、解决方案 (一)检查网络设备状态 nmcli d 发现…...
GitHub绑定本地计算机以及仓库创建跟推送指南
GitHub绑定到本地计算机 要在本地计算机上连接到你的GitHub账户,可以通过以下步骤实现: 1. 检查和安装Git 确保你的计算机上已经安装了Git。如果还没有安装,可以从Git官网下载并安装。 2. 配置Git 打开终端(macOS或Linux&…...
【数据结构】导航
【数据结构】-CSDN博客 【数据结构】next数组、nextval数组-CSDN博客...
Java内存中的Heap(堆)的作用
Java内存中的Heap(堆)的作用 在 Java 的内存模型中,Heap(堆) 是 JVM(Java Virtual Machine)管理的运行时数据区域之一,主要用于存储程序运行过程中动态分配的对象和数据。它是 Java…...
Python控制结构详解
前言 一、控制结构概述 二、顺序结构 三、选择结构(分支结构) 1. 单分支 if 2. 双分支 if-else 3. 多分支 if-elif-else 4.实际应用: 四、循环结构 1. for循环 2. while循环 3. 循环控制语句 五、异常处理(try-except)…...
2023第十四届蓝桥杯大赛软件赛国赛C/C++ 大学 B 组(真题题解)(C++/Java题解)
本来想刷省赛题呢,结果一不小心刷成国赛了 真是个小迷糊〒▽〒 但,又如何( •̀ ω •́ )✧ 记录刷题的过程、感悟、题解。 希望能帮到,那些与我一同前行的,来自远方的朋友😉 大纲: 一、子2023-ÿ…...
JVM介绍
JVM类加载器 栈指令重排序 类的JVM内存分配 堆内存GC模型...
HTML输出流
HTML 输出流 JavaScript 中**「直接写入 HTML 输出流」**的核心是通过 document.write() 方法向浏览器渲染过程中的数据流动态插入内容。以下是详细解释: 一、HTML 输出流的概念 1. 动态渲染过程 HTML 文档的加载是自上而下逐行解析的。当浏览器遇到 <script&…...
Kafka 的高可用性
Kafka 的高可用性主要通过副本机制、ISR(In-Sync Replicas)列表和控制器 Broker 来实现。这些机制共同确保了 Kafka 集群在部分节点故障时仍然可以正常运行,数据不会丢失,并且服务不会中断。 1. 副本机制 Kafka 的副本机制是其高…...
Centos7,tar包方式部署rabbitmq-3.7.6
1. 环境准备 安装编译工具和依赖包 yum -y install make gcc gcc-c glibc-devel m4 perl openssl openssl-devel ncurses-devel ncurses-devel xz xmlto perl 2. Erlang环境搭建 版本对应:https://www.rabbitmq.com/docs/which-erlang 解压到指定目录 tar -xv…...
RISC-V AIA学习3---APLIC 第二部分(APLIC 中断域的内存映射控制区域)
每个中断域都有一个专用的内存映射控制区域,用来处理该中断域的中断。 控制区域的大小是 4KB 的倍数,对齐到 4KB 边界。最小的有效控制区域是 16KB。 1. 控制区域的基本结构:部门文件柜 每个中断域就像公司的一个部门,有自己的 …...
顶刊【遥感目标检测】【TGRS】FFCA-YOLO遥感图像小目标检测
FFCA-YOLO for Small Object Detection in Remote Sensing Images FFCA-YOLO遥感图像小目标检测 0.论文摘要 摘要——特征表征不足、背景干扰等问题使得遥感图像中的小目标检测任务极具挑战性。尤其在算法需部署于星载设备进行实时处理时,需在有限计算资源下对精度…...
【人工智能】从 Llama 到 DeepSeek:开源大模型的演进与技术对比
《Python OpenCV从菜鸟到高手》带你进入图像处理与计算机视觉的大门! 解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界 随着人工智能的迅猛发展,开源大语言模型(LLM)在自然语言处理领域扮演着越来越重要的角色。本文从 Meta 的 Llama 系列开始,追溯开源大模…...
【PCB工艺】时序图(Timing Diagram)
时序图(Timing Diagram)是描述数字电路信号随时间变化的图示,广泛用于分析和设计时序逻辑电路,如锁存器(Latch)、触发器(Flip-Flop)、计数器、状态机等。这篇文章从时序图的原理、构…...
MATLAB 中,并行池(Parallel Pool)自动关闭的情况
在 MATLAB 中,并行池(Parallel Pool)的行为可以通过设置进行控制,但默认情况下,并行池不会自动关闭,除非满足某些条件或显式调用关闭命令。以下是关于并行池自动关闭机制的详细说明: 自动关闭的…...
[网安工具] SQL 注入自动探测工具 —— SQLMAP 使用手册
🌟想了解其它网安工具?看看这个:[网安工具] 网安工具库 —— 工具管理手册 https://github.com/sqlmapproject/sqlmaphttps://github.com/sqlmapproject/sqlmap用法 | sqlmap 用户手册https://sqlmap.highlight.ink/usage 0x01:S…...
Python数据结构与算法-基础预热篇
目录 语言基础 1.内置函数 1.1math库 1.2collections 1.2.1Counter:计数器 1.2.2deque双端对列 1.2.3defaultdict有默认值的字典 1.3heapq堆(完全二叉树) 1.4functool 1.5itertools 1.5.1无限迭代器 1.5.2有限迭代器 1.5.3排列组合迭代器 2.序…...
构建可扩展、可靠的网络抓取、监控和自动化应用程序的终极指南
大家好,这里是架构资源栈!点击上方关注,添加“星标”,一起学习大厂前沿架构! 无论您是企业主、营销人员还是软件开发人员,您都很有可能在某个时候使用过 Web 自动化工具。每个人都希望更聪明地工作…...
【蓝桥杯】重点冲刺
【最高优先级】必考核心算法(占分60%以上) 动态规划(DP) 🌟🌟🌟 背包问题:01背包、完全背包(必须掌握空间优化的一维写法) 线性DP:最长上升子序列(LIS)、最长公共子序列(LCS) 路径问题:网格路径计数(含障碍物)、最小路径和 经典模型:打家劫舍、股票买卖问…...
质量工程师的2025:从“找bug“到“造质量“的职业进化
想象一下,2025年的某天:阅读原文 早晨,AI测试助手已经自动运行了夜间回归测试,并将可疑问题标记出来 你喝着咖啡,通过质量数据看板分析系统健康度 下午的会议上,你正用业务语言向产品经理解释:…...
2025年CNG 汽车加气站操作工题目分享
CNG 汽车加气站操作工题目分享: 单选题 1、CNG 加气站中,加气机的加气软管应( )进行检查。 A. 每天 B. 每周 C. 每月 D. 每季度 答案:A 解析:加气软管是加气操作中频繁使用的部件,每天检…...
【QT5 多线程示例】线程池
线程池 【C并发编程】(九)线程池 QThreadPool 和 QRunnable 是 Qt 提供的线程池管理机制。QRunnable 是一个任务抽象类;定义任务逻辑需要继承QRunnable 并实现 run() 方法。QThreadPool 负责管理线程,并将 QRunnable 任务分配到…...
飞致云荣获“Alibaba Cloud Linux最佳AI镜像服务商”称号
2025年3月24日,阿里云云市场联合龙蜥社区发布“2024年度Alibaba Cloud Linux最佳AI镜像服务商”评选结果。 经过主办方的严格考量,飞致云(即杭州飞致云信息科技有限公司)凭借旗下MaxKB开源知识库问答系统、1Panel开源面板、Halo开…...
FAST-LIVO2 Fast, Direct LiDAR-Inertial-Visual Odometry论文阅读
FAST-LIVO2 Fast, Direct LiDAR-Inertial-Visual Odometry论文阅读 论文下载论文翻译FAST-LIVO2: 快速、直接的LiDAR-惯性-视觉里程计摘要I 引言II 相关工作_直接方法__LiDAR-视觉(-惯性)SLAM_ III 系统概述IV 具有顺序状态更新的误差状态迭代卡尔曼滤波…...
kubesphere 终端shell连不上的问题
使用nginx代理kubesphere控制台会出现容器的终端shell连不上的问题 下面是一个样例配置可以解决这个问题: 注意修改为你的ip地址: upstream k8s { ip_hash; server masterip1:30880; server masterip2:30880; server masterip3:30880; } nginx.conf #…...
无人机,雷达定点飞行时,位置发散,位置很飘,原因分析
参考: 无人车传感器 IMU与GPS数据融合进行定位机制_gps imu 组合定位原始数-CSDN博客 我的无人机使用雷达定位,位置模式很飘 雷达的更新频率也是10HZ, 而px飞控的频率是100HZ,没有对两者之间的频率差异做出处理 所以才导致无人…...
外星人入侵(python设计小游戏)
这个游戏简而言之就是操作一个飞机对前方的飞船进行射击,和一款很久之前的游戏很像,这里是超级低配版那个游戏,先来看看效果图: 由于设计的是全屏的,所以电脑不能截图。。。。 下面的就是你操控的飞船,上面…...
Stereolabs ZED Box Mini:NVIDIA Orin™驱动,双GMSL2输入,智能机器视觉AI新选择”
Stereolabs近日推出了ZED Box Mini,这是一款专为视觉AI设计的紧凑型迷你电脑(ECU)。该产品搭载了NVIDIA Orin™系列处理器,具备强大的AI视觉处理能力,适用于机器人、智能基础设施和工业应用等多种场景。ZED Box Mini以…...
IP协议的介绍
网络层的主要功能是在复杂的网络环境中确定一个合适的路径.网络层的协议主要是IP协议.IP协议头格式如下: 1.4位版本号:指定IP协议的版本,常用的是IPV4,对于IPV4来说,这里的值就是4. 2.4位头部长度,单位也是4个字节,4bit表示的最大数字是15,因此IP头部的最大长度就是60字节 3.…...
【入门初级篇】布局类组件的使用(2)
【入门初级篇】布局类组件的使用(2) 视频要点 (1)2分栏场景介绍与实操演示 (2)3分栏场景介绍与实操演示 点击访问myBuilder产品运营平台 CSDN站内资源下载myBuilder 交流请加微信:MyBuilder8…...
高并发金融系统,“可观测-可追溯-可回滚“的闭环审计体系
一句话总结 在高并发金融系统中,审计方案设计需平衡"观测粒度"与"系统损耗",通过双AOP实现非侵入式采集,三表机制保障操作原子性,最终形成"可观测-可追溯-可回滚"的闭环体系。 业务痛点与需求 在…...
(九)Spring Webflux
底层基于Netty实现的Web容器与请求/响应处理机制 参照:Spring WebFlux :: Spring Frameworkhttps://docs.spring.io/spring-framework/reference/6.0/web/webflux.html 一、组件对比 API功能 Servlet-阻塞式Web WebFlux-响应式Web 前端控制器 DispatcherServl…...
如何在Webpack中配置别名路径?
如何在Webpack中配置别名路径? 文章目录 如何在Webpack中配置别名路径?1. 引言2. 配置别名路径的基本原理3. 如何配置别名路径3.1 基本配置3.2 结合Babel与TypeScript3.2.1 Babel配置3.2.2 TypeScript配置 3.3 适用场景与最佳实践 4. 调试与常见问题4.1 …...
office_word中使用宏以及DeepSeek
前言 Word中可以利用DeepSeek来生成各种宏,从而生成我们需要各种数据和图表,这样可以大大减少我们手工的操作。 1、Office的版本 采用的是微软的office2016,如下图: 2、新建一个Word文档 3、开启开发工具 这样菜单中的“开发工具…...
利用GitHub Pages快速部署前端框架静态网页
文章目录 前言GitHub Pages 来部署前端框架(Vue 3 Vite)项目1、配置 GitHub Pages 部署2、将项目推送到 GitHub3、部署到 GitHub Pages4、访问部署页面5、修改代码后的更新部署顺序 前言 可以先参考: 使用 GitHub Pages 快速部署静态网页: …...
前端性能优化思路_场景题
20 万人同时在直播间打赏,前端优化需要考虑高并发、性能优化、流畅体验等问题,涉及 WebSocket 处理、消息去抖、虚拟列表优化、动画优化、CDN 加速 等多个方面。 WebSocket 高并发优化 (1)使用 WebSocket 替代轮询 轮询…...
45 55跳跃游戏解题记录
先是55跳跃游戏,暴力解法会怎样?会超出时间限制,而且有很多细节要注意: func canJump(nums []int) bool {// 处理空数组情况,当nums只剩一个元素时,nums[i:]导致越界。if len(nums) 0 {return false}// 如…...
一个简单的用C#实现的分布式雪花ID算法
雪花ID是一个依赖时间戳根据算法生成的一个Int64的数字ID,一般用来做主键或者订单号等。以下是一个用C#写的雪花ID的简单实现方法 using System; using System.Collections.Concurrent; using System.Diagnostics;public class SnowflakeIdGenerator {// 配置常量p…...