Python中的线程池与进程池:并行编程的高效选择【第145篇—并行编程】

👽发现宝藏

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。【点击进入巨牛的人工智能学习网站】。

Python中的线程池与进程池:并行编程的高效选择

在Python编程中,实现并行处理任务是提高程序性能的关键。线程池和进程池是Python中常用的并行编程工具,它们能够有效地利用多核处理器的优势,加速程序的执行。本文将介绍线程池和进程池的基本概念,并通过代码示例和解析说明它们的使用方式和优劣势。

线程池与进程池的概念

在介绍线程池和进程池之前,我们先了解一下线程和进程的概念:

  • 线程:线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。
  • 进程:进程是程序的一次执行过程,是操作系统进行资源分配和调度的基本单位。

而线程池和进程池则是对线程和进程的一种管理机制,它们可以预先创建一定数量的线程或进程,然后将任务分配给这些线程或进程执行,从而减少了线程或进程的创建和销毁开销,提高了程序的执行效率。

使用线程池进行并行编程

在Python中,可以使用concurrent.futures模块来创建和管理线程池。下面是一个简单的示例:

import concurrent.futures
import timedef task(n):print(f"Task {n} started")time.sleep(2)print(f"Task {n} finished")if __name__ == "__main__":with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:tasks = [executor.submit(task, i) for i in range(5)]concurrent.futures.wait(tasks)print("All tasks are finished")

在这个示例中,我们定义了一个task函数,模拟了一个需要耗时2秒的任务。然后使用ThreadPoolExecutor创建了一个拥有3个工作线程的线程池,并将5个任务提交给线程池执行。最后通过concurrent.futures.wait等待所有任务完成。

使用进程池进行并行编程

除了线程池,Python也提供了concurrent.futures模块来创建和管理进程池。下面是一个使用进程池的示例:

import concurrent.futures
import timedef task(n):print(f"Task {n} started")time.sleep(2)print(f"Task {n} finished")if __name__ == "__main__":with concurrent.futures.ProcessPoolExecutor(max_workers=3) as executor:tasks = [executor.submit(task, i) for i in range(5)]concurrent.futures.wait(tasks)print("All tasks are finished")

这个示例与线程池的示例类似,只是将ThreadPoolExecutor替换为ProcessPoolExecutor,创建了一个拥有3个工作进程的进程池。

代码解析

  • 在使用线程池和进程池时,通过ThreadPoolExecutorProcessPoolExecutor可以分别创建线程池和进程池。
  • max_workers参数指定了线程池或进程池中工作线程或进程的数量,根据CPU核心数和任务的性质可以进行调整。
  • 使用submit方法提交任务给线程池或进程池执行,该方法会返回一个Future对象,可以用来获取任务执行的状态和结果。
  • wait方法用于等待所有任务完成,确保主线程在所有任务完成后再继续执行。

线程池与进程池的选择

在选择线程池或进程池时,需要考虑到任务的性质以及计算机资源的情况。

线程池的优势:

  1. 轻量级: 线程相比进程更加轻量级,创建和销毁线程的开销较小。
  2. 共享内存: 线程之间共享同一进程的内存空间,数据共享更加方便。
  3. 适用于IO密集型任务: 当任务主要是等待IO操作时,线程池能够更好地利用CPU资源,因为线程在等待IO时可以释放GIL(全局解释器锁)。

进程池的优势:

  1. 更好的并行性: 不受GIL限制,多进程能够更好地利用多核处理器,适用于CPU密集型任务。
  2. 更好的隔离性: 每个进程拥有独立的内存空间,数据共享需要通过显式的IPC(进程间通信)机制,因此更加安全稳定。

因此,在选择线程池或进程池时,可以根据任务的性质和计算机资源来进行权衡。如果任务主要是IO密集型的,且需要较少的系统资源,那么线程池可能是更好的选择;而如果任务是CPU密集型的,且需要更好的并行性能,那么进程池可能更合适。

并发编程中的常见问题与解决方案

在使用线程池和进程池进行并发编程时,可能会遇到一些常见的问题,如竞态条件、死锁、资源争夺等。下面我们将介绍这些问题以及相应的解决方案:

  1. 竞态条件(Race Condition): 当多个线程或进程同时访问共享资源,并试图对资源进行修改时,由于执行顺序不确定而导致的问题。解决方案包括使用锁(Lock)、信号量(Semaphore)等同步机制来保护共享资源的访问,以确保同一时间只有一个线程或进程可以修改共享资源。

  2. 死锁(Deadlock): 当多个线程或进程互相持有对方所需的资源,并等待对方释放资源时,导致所有线程或进程无法继续执行的情况。解决方案包括按顺序获取资源、避免持有资源的时间过长、使用超时机制等来防止死锁的发生。

  3. 资源争夺(Resource Starvation): 当某个线程或进程长时间占用了某个资源,导致其他线程或进程无法获得该资源而无法继续执行的情况。解决方案包括合理地分配资源、使用队列等待资源、使用优先级调度等来避免资源争夺问题。

  4. 数据共享与同步: 在多线程或多进程环境中,需要对共享数据进行合理的访问和同步,以避免数据不一致的问题。解决方案包括使用同步原语(如锁、信号量、事件等)来保护共享数据的访问,以及使用线程安全的数据结构来避免数据竞争。

  5. 性能与扩展性: 在设计并发程序时,需要考虑性能和扩展性的平衡,以充分利用多核处理器的性能优势,并保持程序的可扩展性。解决方案包括合理地选择线程池或进程池的大小、优化任务调度算法、使用异步编程模型等来提高程序的性能和扩展性。

通过以上解决方案的应用,可以有效地解决并发编程中常见的问题,保证程序的正确性和稳定性,并提高程序的性能和扩展性。

进一步优化并行编程

除了处理常见的并发编程问题外,还可以通过一些技巧和策略进一步优化并行编程的效率和性能:

  1. 任务分解与合并: 将大任务分解成小任务,并将这些小任务分配给线程池或进程池执行,然后再将结果合并。这样可以更好地利用多核处理器的并行性能,并减少任务调度的开销。

  2. 批量处理: 将多个任务合并成一个批量任务,然后一次性提交给线程池或进程池执行。这样可以减少任务调度的次数,提高程序的执行效率。

  3. 异步编程: 使用异步编程模型(如asyncio、aiohttp等)来实现非阻塞式的并发处理,提高程序的响应速度和并发能力。异步编程可以避免线程或进程之间的上下文切换开销,从而提高程序的性能。

  4. 任务优先级调度: 根据任务的优先级来调度线程或进程的执行顺序,优先处理优先级高的任务,以提高程序的响应速度和用户体验。

  5. 动态调整线程池或进程池大小: 根据系统负载和任务量动态调整线程池或进程池的大小,以充分利用系统资源并避免资源浪费。

通过以上优化技巧和策略的应用,可以进一步提高并行编程的效率和性能,实现更加高效的程序执行。

示例代码

下面是一个使用异步编程模型的示例代码:

import asyncioasync def task(n):print(f"Task {n} started")await asyncio.sleep(2)print(f"Task {n} finished")async def main():tasks = [task(i) for i in range(5)]await asyncio.gather(*tasks)print("All tasks are finished")if __name__ == "__main__":asyncio.run(main())

在这个示例中,我们使用了asyncio模块来实现异步编程,通过asyncawait关键字定义了异步任务,并使用asyncio.gather来并发执行多个任务,最后通过asyncio.run来运行主函数。

监控与调优

一旦并行程序运行起来,监控其性能并进行调优也是至关重要的。这可以通过以下方式实现:

  1. 性能监控工具: 使用性能监控工具(如tophtoppsutil等)监视程序的CPU、内存和IO等资源的使用情况,以及线程池或进程池的工作状态。

  2. 日志记录: 在程序中添加日志记录,记录关键事件和性能指标,以便后续分析和优化。

  3. 性能分析工具: 使用性能分析工具(如cProfileline_profiler等)分析程序的性能瓶颈,找出影响程序性能的热点代码和慢速函数,并进行优化。

  4. 内存管理: 注意内存的使用情况,避免内存泄漏和过度分配内存,合理管理内存资源,以提高程序的性能和稳定性。

  5. 调优策略: 根据监控和分析结果,针对性地进行调优,包括调整线程池或进程池的大小、优化算法和数据结构、减少IO操作等,以达到最佳的性能和资源利用率。

通过持续监控和调优,并不断优化并行程序的性能,可以使程序达到更高的性能水平,并提高用户的体验和满意度。

示例代码

以下是一个简单的性能监控示例,使用psutil库来监视CPU和内存的使用情况:

import psutil
import timedef monitor_performance(interval=1):while True:cpu_percent = psutil.cpu_percent(interval=interval)memory_percent = psutil.virtual_memory().percentprint(f"CPU 使用率:{cpu_percent}%,内存 使用率:{memory_percent}%")time.sleep(interval)if __name__ == "__main__":monitor_performance()

这个示例会每隔1秒钟打印一次当前的CPU使用率和内存使用率。

处理异常和错误

在并行编程中,处理异常和错误是非常重要的,因为多线程或多进程的执行过程中可能会出现各种意外情况。以下是一些处理异常和错误的常见方法:

  1. 异常捕获: 在任务函数中使用try-except语句捕获可能发生的异常,并进行适当的处理或记录日志。
import concurrent.futuresdef task(n):try:# 执行任务的代码except Exception as e:print(f"Task {n} encountered an exception: {e}")
  1. 异常传播: 在任务函数中捕获异常后,可以选择将异常传播给调用者,以便在上层进行统一处理或回滚操作。

  2. 异常处理器: 可以为线程池或进程池设置异常处理器,在任务执行过程中发生异常时调用指定的异常处理函数。

import concurrent.futuresdef handle_exception(exception, context):print(f"An exception occurred: {exception}")with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:executor.set_exception_handler(handle_exception)# 提交任务给线程池执行
  1. 超时处理: 在执行任务时设置超时时间,并在超时后进行相应的处理,如取消任务或重新提交任务。
import concurrent.futuresdef task(n):# 执行任务的代码with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:future = executor.submit(task, 123)try:result = future.result(timeout=1)except concurrent.futures.TimeoutError:print("Task execution timed out")

通过适当地处理异常和错误,可以提高并行程序的稳定性和可靠性,减少意外情况对程序的影响。

示例代码

以下是一个示例代码,演示了如何在并行编程中处理异常:

import concurrent.futuresdef task(n):try:result = 1 / nprint(f"Task {n} result: {result}")except ZeroDivisionError:print(f"Task {n} encountered a division by zero error")if __name__ == "__main__":with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:tasks = [executor.submit(task, i) for i in range(5)]concurrent.futures.wait(tasks)print("All tasks are finished")

在这个示例中,任务函数task会对传入的参数进行除法操作,如果参数为0,则会抛出ZeroDivisionError异常。任务函数中使用了try-except语句来捕获可能的异常,并打印相应的错误信息。

数据同步与共享

在并行编程中,多个线程或进程可能需要共享数据或进行数据同步,因此正确地处理数据同步与共享是至关重要的。以下是一些常见的数据同步与共享的方法:

  1. 锁(Lock): 使用锁来保护共享资源的访问,确保同一时间只有一个线程或进程可以修改共享资源,从而避免竞态条件和数据不一致的问题。
import threadingshared_resource = 0
lock = threading.Lock()def update_shared_resource():global shared_resourcewith lock:shared_resource += 1
  1. 条件变量(Condition): 使用条件变量来实现线程间的通信和同步,其中一个线程负责产生条件变量的条件,另一个线程负责检查条件并执行相应的操作。
import threadingcondition = threading.Condition()
flag = Falsedef producer():global flagwith condition:flag = Truecondition.notify()def consumer():global flagwith condition:while not flag:condition.wait()# 执行消费者操作
  1. 信号量(Semaphore): 使用信号量来限制同时访问共享资源的线程或进程数量,控制并发访问。
import threadingsemaphore = threading.Semaphore(3)def access_shared_resource():with semaphore:# 执行对共享资源的访问操作
  1. 事件(Event): 使用事件来进行线程间的通信和同步,一个线程可以设置事件并通知其他线程,其他线程可以等待事件的触发并执行相应的操作。
import threadingevent = threading.Event()def worker():event.wait()# 执行相应的操作def set_event():event.set()

通过合理地使用这些方法,可以确保多个线程或进程之间的数据同步和共享的正确性和可靠性,避免出现竞态条件和数据不一致的问题。

示例代码

以下是一个简单的示例代码,演示了如何使用锁来保护共享资源的访问:

import threadingshared_resource = 0
lock = threading.Lock()def update_shared_resource():global shared_resourcewith lock:shared_resource += 1if __name__ == "__main__":threads = []for _ in range(10):t = threading.Thread(target=update_shared_resource)t.start()threads.append(t)for t in threads:t.join()print("Shared resource value:", shared_resource)

在这个示例中,多个线程同时执行update_shared_resource函数来更新共享资源shared_resource的值,通过锁来保护对共享资源的访问,确保线程安全。

高级并行编程技术

除了基本的线程池和进程池之外,还有一些高级的并行编程技术可以进一步提高程序的性能和扩展性:

  1. 分布式计算: 使用分布式计算框架(如Dask、Apache Spark等)将任务分布到多台计算机上进行并行处理,以充分利用集群的计算资源,实现大规模数据处理和分布式计算。

  2. GPU加速: 使用图形处理器(GPU)进行并行计算,通过CUDA、OpenCL等GPU编程框架来实现并行计算任务的加速,尤其适用于科学计算、机器学习等需要大量数值计算的应用领域。

  3. 并行算法和数据结构: 设计并实现高效的并行算法和数据结构,以减少并行计算过程中的竞争和冲突,提高程序的并行性能和扩展性。

  4. 流式处理: 使用流式处理框架(如Apache Kafka、Apache Flink等)来实现数据流的实时处理和分布式计算,以处理大数据量和实时数据流,并支持高吞吐量和低延迟的数据处理需求。

  5. 异构计算: 结合CPU、GPU、FPGA等异构计算设备,根据任务的特点和计算资源的情况选择合适的计算设备进行并行计算,以提高计算资源的利用率和整体性能。

通过应用这些高级的并行编程技术,可以进一步提高程序的性能和扩展性,实现更加高效和灵活的并行计算和数据处理。

示例代码

以下是一个简单的示例代码,演示了如何使用Dask来实现分布式计算:

import dask
import dask.array as da# 创建一个随机数组
x = da.random.random((10000, 10000), chunks=(1000, 1000))# 计算数组的平均值
mean = x.mean()print("Mean:", mean.compute())

在这个示例中,我们使用Dask创建了一个大型的随机数组,并计算了该数组的平均值。Dask会自动将数组分成多个块,并将计算任务分布到多个计算节点上进行并行处理,以实现分布式计算。

可视化与分析

在并行编程中,对程序的运行状态进行可视化和分析可以帮助开发者更好地理解程序的执行过程,发现潜在的性能瓶颈和优化空间。以下是一些可视化与分析的方法:

  1. 性能分析工具: 使用性能分析工具(如cProfileline_profilermemory_profiler等)对程序进行性能分析,分析程序的运行时间、内存占用和函数调用等情况,找出性能瓶颈和潜在的优化空间。

  2. 图形化界面: 开发图形化界面来监控程序的运行状态和性能指标,实时显示任务的执行进度、CPU和内存的使用情况,以及可能的异常和错误信息,帮助开发者及时发现和解决问题。

  3. 日志记录与分析: 在程序中添加日志记录,记录关键事件和性能指标,使用日志分析工具对日志进行分析和统计,发现程序的异常和错误,以及可能的性能瓶颈和优化建议。

  4. 可视化工具: 使用可视化工具(如Matplotlib、Seaborn、Plotly等)对程序的执行结果进行可视化,绘制图表和图形来展示数据的分布、趋势和关联性,帮助开发者更直观地理解程序的运行情况和数据特征。

通过可视化和分析,可以更全面地了解程序的执行过程和性能特征,发现潜在的问题和优化空间,并采取相应的措施进行优化和改进。

示例代码

以下是一个简单的示例代码,演示了如何使用Matplotlib对程序的执行结果进行可视化:

import matplotlib.pyplot as plt# 模拟生成一些数据
x = range(10)
y = [i**2 for i in x]# 绘制折线图
plt.plot(x, y)
plt.xlabel('X')
plt.ylabel('Y')
plt.title('Example Plot')
plt.grid(True)
plt.show()

在这个示例中,我们使用Matplotlib绘制了一个简单的折线图,展示了数据的分布和趋势。

总结

并行编程是提高程序性能和扩展性的重要手段,通过合理地利用多核处理器和分布式计算资源,可以实现任务的并行执行,加速程序的运行速度,处理大规模数据和复杂计算任务。本文介绍了在Python中进行并行编程的各种技术和方法,包括线程池、进程池、异常处理、数据同步与共享、高级并行编程技术等。

首先,我们介绍了线程池和进程池作为实现并行编程的基本工具,它们分别适用于不同类型的任务和计算机资源的情况。然后,我们讨论了并发编程中常见的问题和解决方案,包括异常处理、数据同步与共享、监控与调优等。接着,我们介绍了一些高级的并行编程技术,如分布式计算、GPU加速、流式处理等,以进一步提高程序的性能和扩展性。最后,我们讨论了可视化与分析在并行编程中的重要性,通过对程序的运行状态和性能指标进行可视化和分析,可以更好地发现问题和优化空间,提高程序的性能和用户体验。

综上所述,通过合理地选择并使用并行编程技术和方法,并结合可视化与分析技术进行监控与调优,可以实现更加高效和稳定的并行计算和数据处理,提高程序的性能和扩展性,满足不同应用场景的需求。因此,在开发并行程序时,开发者应该充分了解并掌握各种并行编程技术和方法,并根据具体的应用场景和任务特点进行合理的选择和应用,以达到最佳的性能和用户体验。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/282832.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[Linux]条件变量:实现线程同步(什么是条件变量、为什么需要条件变量,怎么使用条件变量(接口)、例子,代码演示(生产者消费者模式))

目录 一、条件变量 1.什么是条件变量 故事说明 2、为什么需要使用条件变量 竞态条件 3.什么是同步 饥饿问题 二、条件变量的接口 1.pthread_cond_t 2.初始化(pthread_cond_init) 3.销毁(pthread_cond_destroy) 4.等待&…

联发科MT8797迅鲲1300T规格参数_MTK5G安卓核心板方案定制

联发科MT8797(迅鲲1300T)平台采用Arm Cortex-A78和Cortex-A55组成的八核架构CPU,以及Arm Mali-G77MC9九核GPU,集成了AI处理器MediaTek APU,支持5G Sub-6GHz全频段和5G双载波聚合,支持1.08亿像素拍照和多镜头组合,以及1…

《逆水寒》“公费追星”被骂上热搜,玩家为何如此抗拒剧游联动?

游戏行业最近真是风波不断。 《逆水寒》手游因为和武侠剧《莲花楼》深入联动而遭到玩家抵制,网易游戏测评总监被质疑“公费追星”,还波及到了成毅、陈都灵等多位演员。 尤其是《莲花楼》的男主角成毅,遭到大量《逆水寒》手游玩家的吐槽调侃…

Java项目:70 ssm小学生课外知识学习网站+vue

作者主页:源码空间codegym 简介:Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 管理员;首页、个人中心、医护人员管理、科室管理、病人管理、病房管理、病人信息管理、病历管理、医嘱管理、手术安排管理、药品信…

Shell脚本学习-if循环

最小化的if语句 无实际用途 if [ ] ;then echo fi 脚本解释 if 判断 [ ] 里面的条件是否成立 后面跟then,代表条件成立 如果在一行则使用分号隔离(;) 如果不在一行使用则直接在下一行驶入then即可。 如果条件成立则输出echo 后面…

GEC6818——QT开发之两个UI界面切换与表格显示DHT11数据

GEC6818——QT开发之两个UI界面切换与表格显示DHT11数据 使用环境: ubantu16 QT5.7 开发板GEC6818 实现要求: 利用A53按键1、按键2与温湿度传感器完成QT界面动态显示温湿度记录,并指定温湿度记录超过指定范围,进行报警(LED&#…

企业网络基础设施物理安全面临全新挑战

企业网络基础设施的物理安全是确保业务连续性和数据完整性的关键组成部分。随着技术的发展和环境的变化,这些基础设施面临着新的挑战。以下是一些主要的挑战和的解决方案 一、机房、仓库、档案馆物理安全事件频发的挑战: 1.电力安全事件:市…

HTML5+CSS3+JS小实例:创意罗盘时钟

实例:创意罗盘时钟 技术栈:HTML+CSS+JS 效果: 源码: 【HTML】 <!DOCTYPE html> <html lang="zh-CN"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=…

优惠:阿里云4核16G服务器优惠价格26.52元1个月、149.00元半年

阿里云4核16G服务器优惠价格26.52元1个月、79.56元3个月、149.00元半年&#xff0c;配置为阿里云服务器ECS经济型e实例ecs.e-c1m4.xlarge&#xff0c;4核16G、按固定带宽 10Mbs、100GB ESSD Entry系统盘&#xff0c;活动链接 aliyunfuwuqi.com/go/aliyun 活动链接打开如下图&a…

网络安全实训Day5

写在前面 昨天忘更新了......讲的内容不多&#xff0c;就一个NAT。 之前记的NAT的内容&#xff1a;blog.csdn.net/Yisitelz/article/details/131840119 网络安全实训-网络工程 NAT 公网地址与私网地址 公网地址 可以在互联网上被寻址&#xff0c;由运营商统一分配全球唯一的I…

苹果手机更换国内IP地址的方法

在网络世界中&#xff0c;IP地址扮演着极为重要的角色&#xff0c;是互联网通信的基础。很多人在使用苹果手机时&#xff0c;有时候需要更换国内IP地址以获取更多网络资源或保护隐私。那么&#xff0c;是否可以更换国内ip地址&#xff1f;苹果手机更换国内ip地址的方法是怎样的…

阿兹特克帝国社会结构和政治农业和经济宗教和文化西班牙征服和遗产特诺奇提特兰(Tenochtitlán)地理位置和建筑社会和经济水上花园和农业西班牙征服巴斯克人

目录 阿兹特克帝国 社会结构和政治 农业和经济 宗教和文化 西班牙征服和遗产 特诺奇提特兰&#xff08;Tenochtitln&#xff09; 地理位置和建筑 社会和经济 水上花园和农业 西班牙征服 巴斯克人 语言 历史 文化和社会 政治和自治 1. 新南威尔士大学最新资讯 …

vue学习日记14:工程化开发脚手架Vue CLI

一、概念 二、安装 1.全局安装&查看版本 注意启动cmd输入命令 要以管理员运行哦 安装了一次就行以后不用再创建了 yarn global addvue/cli vue --version 显示了版本号即可 2.创建项目架子 创建项目的路径在哪 项目就在哪 项目名字不能用中文 vue create project-n…

Legacy|电脑Windows系统如何迁移到新安装的硬盘?系统迁移详细教程!

前言 前面讲了很多很多关于安装系统、重装系统的教程。但唯独没有讲到电脑换了新的硬盘之后&#xff0c;怎么把旧系统迁移到新的硬盘上。 今天小白就来跟各位小伙伴详细唠唠&#xff1a; 开始之前需要把系统迁移的条件准备好&#xff0c;意思就是在WinPE系统下&#xff0c;可…

子组件自定义事件$emit实现新页面弹窗关闭之后父界面刷新

文章目录 需求弹窗关闭之后父界面刷新展示最新数据 实现方案AVUE 大文本默认展开slotVUE 自定义事件实现 父界面刷新那么如何用呢? 思路核心代码1. 事件定义2. 帕斯卡命名组件且在父组件中引入以及注册3. 子组件被引用与父事件监听4.父组件回调函数 5.按钮弹窗事件 需求 弹窗…

大屏动效合集更更更之实现百分比环形

实现效果 参考链接&#xff1a; https://pslkzs.com/demo/pie/demo1.php 写在最后&#x1f352; 源码&#xff0c;关注&#x1f365;苏苏的bug&#xff0c;&#x1f361;苏苏的github&#xff0c;&#x1f36a;苏苏的码云

贪心算法(算法竞赛、蓝桥杯)--奶牛晒衣服

1、B站视频链接&#xff1a;A28 贪心算法 P1843 奶牛晒衣服_哔哩哔哩_bilibili 题目链接&#xff1a;奶牛晒衣服 - 洛谷 #include <bits/stdc.h> using namespace std; priority_queue<int> q;//用大根堆维护湿度的最大值 int n,a,b; int tim,maxn;int main(){s…

代码随想录算法训练营第day54|392.判断子序列 、 115.不同的子序列

目录 392.判断子序列 115.不同的子序列 392.判断子序列 力扣题目链接(opens new window) 给定字符串 s 和 t &#xff0c;判断 s 是否为 t 的子序列。 字符串的一个子序列是原始字符串删除一些&#xff08;也可以不删除&#xff09;字符而不改变剩余字符相对位置形成的新字…

Vue2(三):绑定样式、条件渲染(v-if,v-show)、列表渲染(v-for)、key的原理、列表过滤、列表排序

一、绑定样式 1.绑定class样式 (1)字符串写法 适用于&#xff1a;样式类名不确定&#xff0c;需要动态获取。 <div id"root"><div class"basic" :class"mood" click"changeMood">test</div><!-- class是原本的…

Linux(openEuler)部署SpringBoot前后端分离项目(Nginx负载均衡)

假如数据库在本地&#xff0c;没有放在Linux中 1.先把数据库中root的主机改成% 2.项目中的数据库链接配置换成本机ip 3.打包 4.把打包好的jar包放到Linux中 一般把jar包放到opt下 5.把前端部分拷贝到Linux的nginx中 5.1在package.json中修改build的值为图中这样 5.2同时由于在…