实战Concurrent

Qt Concurrent实战:从基础API到高效并行编程技巧 本文深入探讨Qt Concurrent框架在并行编程中的实战应用,从基础API到高效技巧全面解析。通过实际案例展示如何利用QtConcurrent::map()、run()等核心API优化图像处理、数据分析等场景,提升多线程编程效率。文章特别强调自动线程管理、无锁编程等Qt Concurrent核心优势,并分享任务分块、线程池定制等高级优化策略。 阅读详情

编写多线程的程序一直都是一件比较麻烦的事情,要考虑很多事情,处理不好还会出很多意想不到的麻烦。加上现在很多开发者接触到的项目都是打着企业级旗号的B/S项目,大多数人都很少涉及多线程,这又为本文的主角增加了一份神秘感。

讲到Java多线程,大多数人脑海中跳出来的是Thread、Runnable、synchronized……这些是最基本的东西,虽然已经足够强大,但想要用好还真不容易。从JDK 1.5开始,增加了java.util.concurrent包,它的引入大大简化了多线程程序的开发(要感谢一下大牛Doug Lee)。

java.util.concurrent包分成了三个部分,分别是java.util.concurrent、 java.util.concurrent.atomic和java.util.concurrent.lock。内容涵盖了并发集合类、线程池机制、同步互斥机制、线程安全的变量更新工具类、锁等等常用工具。

为了便于理解,本文使用一个例子来做说明,交代一下它的场景:

假设要对一套10个节点组成的环境进行检查,这个环境有两个入口点,通过节点间的依赖关系可以遍历到整个环境。依赖关系可以构成一张有向图,可能存在环。为了提高检查的效率,考虑使用多线程。

 

1、Executors
通过这个类能够获得多种线程池的实例,例如可以调用newSingleThreadExecutor()获得单线程的 ExecutorService,调用newFixedThreadPool()获得固定大小线程池的ExecutorService。拿到 ExecutorService可以做的事情就比较多了,最简单的是用它来执行Runnable对象,也可以执行一些实现了 Callable<T>的对象。用Thread的start()方法没有返回值,如果该线程执行的方法有返回值那用 ExecutorService就再好不过了,可以选择submit()、invokeAll()或者invokeAny(),根据具体情况选择合适的方法即可。

这里要额外说明一下invokeAll()和invokeAny()方法。前者会执行给定的所有Callable<T>对象,等所有任务完成后返回一个包含了执行结果的List<Future<T>>,每个Future.isDone()都是true,可以用 Future.get()拿到结果;后者只要完成了列表中的任意一个任务就立刻返回,返回值就是执行结果。

 

还有一个比较诡异的地方
本代码是在JDK 1.6下编译测试的,如果在JDK 1.5下测试,很可能在invokeAll和invokeAny的地方出错。明明ValidationTask实现了 Callable<Node>,可是它死活不认,类型不匹配,这时可以将参数声明由List<ValidationTask>改为 List<Callable<Node>>。
造成这个问题的主要原因是两个版本中invokeAll和invokeAny的方法签名不同,1.6里是 invokeAll(Collection<? extends Callable<T>> tasks),而1.5里是invokeAll(Collection<Callable<T>> tasks)。网上也有人遇到类似的问题(invokeAll() is not willing to acept a Collection<Callable<T>> )。

和其他资源一样,线程池在使用完毕后也需要释放,用shutdown()方法可以关闭线程池,如果当时池里还有没有被执行的任务,它会等待任务执行完毕,在等待期间试图进入线程池的任务将被拒绝。也可以用shutdownNow()来关闭线程池,它会立刻关闭线程池,没有执行的任务作为返回值返回。

 

2、Lock
多线程编程中常常要锁定某个对象,之前会用synchronized来实现,现在又多了另一种选择,那就是 java.util.concurrent.locks。通过Lock能够实现更灵活的锁定机制,它还提供了很多synchronized所没有的功能,例如尝试获得锁(tryLock())。

使用Lock时需要自己获得锁并在使用后手动释放,这一点与synchronized有所不同,所以通常Lock的使用方式是这样的:

java.util.concurrent.locks中提供了几个Lock接口的实现类,比较常用的应该是ReentrantLock。以下范例中使用了ReentrantLock进行节点锁定:

请注意ValidationTask的call()方法,这里会先检查节点是否被锁定,如果被锁定则表示当前有另一个线程正在验证该节点,那就不用重复进行验证。第50行和第51行,那到锁后立即释放,这里只是为了等待验证结束。

讲到Lock,就不能不讲Conditon,前者代替了synchronized,而后者则代替了Object对象上的wait()、 notify()和notifyAll()方法(Condition中提供了await()、signal()和signalAll()方法),当满足运行条件前挂起线程。Condition是与Lock结合使用的,通过Lock.newCondition()方法能够创建与Lock绑定的 Condition实例。JDK的JavaDoc中有一个例子能够很好地说明Condition的用途及用法:

说到这里,让我解释一下之前的例子里为什么没有选择Condition来等待验证结束。await()方法在调用时当前线程先要获得对应的锁,既然我都拿到锁了,那也就是说验证已经结束了。。。

3、并发集合类
集合类是大家编程时经常要使用的东西,ArrayList、HashMap什么的,java.util包中的集合类有的是线程安全的,有的则不是,在编写多线程的程序时使用线程安全的类能省去很多麻烦,但这些类的性能如何呢?java.util.concurrent包中提供了几个并发结合类,例如 ConcurrentHashMap、ConcurrentLinkedQueue和CopyOnWriteArrayList等等,根据不同的使用场景,开发者可以用它们替换java.util包中的相应集合类。

CopyOnWriteArrayList是ArrayList的一个变体,比较适合用在读取比较频繁、修改较少的情况下,因为每次修改都要复制整个底层数组。ConcurrentHashMap中为Map接口增加了一些方法(例如putIfAbsenct()),同时做了些优化,总之灰常之好用,下面的代码中使用ConcurrentHashMap来作为全局节点表,完全无需考虑并发问题。ValidationService中只是声明(第17 行),具体的使用是在上面的ValidationTask中。

4、AtomicInteger
对变量的读写操作都是原子操作(除了long或者double的变量),但像数值类型的++ --操作不是原子操作,像i++中包含了获得i的原始值、加1、写回i、返回原始值,在进行类似i++这样的操作时如果不进行同步问题就大了。好在 java.util.concurrent.atomic为我们提供了很多工具类,可以以原子方式更新变量。

以AtomicInteger为例,提供了代替++ --的getAndIncrement()、incrementAndGet()、getAndDecrement()和 decrementAndGet()方法,还有加减给定值的方法、当前值等于预期值时更新的compareAndSet()方法。

下面的例子中用AtomicInteger保存全局验证次数(第69行做了自增的操作),因为validateNode()方法会同时被多个线程调用,所以直接用int不同步是不行的,但用AtomicInteger在这种场合下就很合适。

上述代码还有另一个功能,就是构造测试用的节点数据,一共10个节点,有2个入口点,通过这两个点能够遍历整个系统。每次调用会模拟远程访问,等待500ms。环境间节点依赖如下:

环境依赖
Node0 [Node1, Node2]
Node1 [Node3, Node4]
Node2 [Node5]
Node6 [Node7, Node8]
Node7 [Node5, Node9]
Node8 [Node3, Node4]

5、CountDownLatch
CountDownLatch是一个一次性的同步辅助工具,允许一个或多个线程一直等待,直到计数器值变为0。它有一个构造方法,设定计数器初始值,即在await()结束等待前需要调用多少次countDown()方法。CountDownLatch的计数器不能重置,所以说它是“一次性”的,如果需要重置计数器,可以使用CyclicBarrier。在运行环境检查的主类中,使用了CountDownLatch来等待所有验证结束,在各个并发验证的线程完成任务结束前都会调用countDown(),因为有3个并发的验证,所以将计数器设置为3。

最后将所有这些类整合起来,运行环境检查的主类如下。它会创建线程池服务和验证服务,先做一次验证(相当于是对系统做次初始化),随后并发3个验证请求。系统运行完毕会显示实际执行的节点验证次数和执行时间。如果是顺序执行,验证次数应该是13*4=52,但实际的验证次数会少于这个数字(我这里最近一次执行了33次验证),因为如果同时有两个线程要验证同一节点时只会做一次验证。关于时间,如果是顺序执行,52次验证每次等待500ms,那么验证所耗费的时间应该是26000ms,使用了多线程后的实际耗时远小于该数字(最近一次执行耗时4031ms)。

 

本文没有覆盖java.util.concurrent中的所有内容,只是挑选一些比较常用的东西,想要获得更多详细信息请阅读JavaDoc。自打有了 “轮子”理论,重复造大轮子的情况的确少了,但还是有人会做些小轮子,例如编写多线程程序时用到的小工具(线程池、锁等等),如果可以,请让自己再“懒惰 ”一点吧~

Ruby并发编程实战:concurrent-ruby核心原理与应用指南 并发编程是现代软件开发中的关键技术,旨在解决程序在等待耗时操作时阻塞其他任务执行的问题,从而更高效地利用系统资源。其核心原理是通过多线程、异步执行等机制,让多个任务能够同时或交替执行。在Ruby生态中,由于MRI的全局解释器锁(GIL)限制,原生多线程在CPU密集型任务上性能受限,而手动管理线程又容易引入竞态条件和死锁等难题。concurrent-ruby库的价值在于,它将Java、Scala等语言中成熟的并发模式引入Ruby,提供了高级、安全的抽象层,如Future/Promise、线程池、线程安全数据结 阅读详情

相关推荐

从零到一:Qt Concurrent在GUI优化中的实战技巧

本文深入探讨了Qt Concurrent在GUI优化中的实战应用,通过并发编程解决界面卡顿问题。文章详细介绍了Qt Concurrent的核心功能,包括任务并行、数据并行和流水线并行,并提供了图像处理优化的实际案例和性能对比,帮助开发者提升应用流畅度。

weixin_29233333的博客 260

《Python实战进阶》No44: 并发框架:concurrent.futures 的使用(下)

`concurrent.futures` 是 Python 标准库中简化并发编程的核心工具,通过 **线程池(ThreadPoolExecutor)** 和 **进程池(ProcessPoolExecutor)** 实现高效的并发任务调度。本篇结合实战案例,在上集中,我们结合 Future 对象和回调机制,通过两个实战案例”API 请求并发处理”,“矩阵运算并行化“展示如何通过上下文管理器优雅地管理资源。在本文,我们将巩固所学知识,演示如何通过 `submit()`、`map()` 等方法并行化处理 I/O

yweng18的博客 1961

Python并发编程实战:用concurrent.futures榨干CPU性能的终极指南

线程池:适合网络请求、文件IO等等待型操作进程池:适合数学计算、图像处理等CPU密集型任务混合架构:复杂场景下的终极解决方案先测量,后优化:用cProfile找出性能瓶颈资源节制:控制最大工作线程/进程数优雅关闭:使用上下文管理器确保资源释放通过合理运用,你不仅能将程序性能提升十倍以上,更能写出专业级的高效代码。现在就去给你的程序装上“涡轮增压器”吧!

铭渊老黄 354

Qt Concurrent异步编程实战:QFuture与QFutureWatcher的深度协同

本文深入探讨了Qt Concurrent异步编程中QFuture与QFutureWatcher的深度协同应用。通过一个文件批量处理器的实战案例,详细解析了如何利用这对组合实现后台计算与前台UI的无缝通信,有效解决界面卡顿问题,并涵盖进度监控、任务控制及线程安全等核心实践。

tensor9flow的博客 652

《Python 并发编程实战:用 concurrent.futures 优雅处理多任务》

本文介绍了Python并发编程中的concurrent.futures模块,通过实战案例展示如何优雅处理多任务。文章首先分析了Python并发编程的选择,指出concurrent.futures模块统一了线程池和进程池接口,简化了并发任务管理。随后详细演示了线程池处理I/O密集型任务和进程池处理CPU密集型任务的具体实现,包括异常处理和超时控制等关键技巧。最后提出了最佳实践建议,并探讨了与异步编程的融合可能。该模块能显著提升Python程序的并发性能,特别适合批量数据处理、网络请求等场景。

铭渊老黄 96

从0开始学GEE python——Google Earth Engine (GEE) 和 geemap 库来获取 Sentinel-2 卫星影像,并将其可视化

这段代码的目的是从 Sentinel-2 卫星影像中获取特定地点的影像,并将其可视化在地图上。通过设置合适的波段和可视化参数,用户可以清晰地查看该地区的卫星影像。

此星光明博客 1167

concurrent.futures 全面教程:常用 API 串联与实战指南

Python并发编程实战:concurrent.futures模块详解 摘要: 本文深入解析Python标准库中的concurrent.futures模块,该模块通过Executor抽象类简化并发编程。教程详细介绍了ThreadPoolExecutor(线程池)和ProcessPoolExecutor(进程池)的适用场景,全面拆解了从创建执行器到任务管理的核心API,包括submit()、result()、as_completed()等关键方法。通过连贯的代码示例演示了如何高效执行并行任务,并提供了线程/进

jobleap.cn求职助手首页 1156

实战分享:如何用Dify和MaxKb实现文档智能切分与高效检索(附代码解析)

本文详细介绍了如何结合Dify和MaxKB构建文档智能切分与高效检索系统。针对传统全文检索的不足,提出了结构感知的文档切分方案,通过解析文档层级关系并构建标题链,实现了精准的章节级检索。文章包含完整的代码实现,涵盖文档解析、智能切分、向量化策略及双索引优化,并分享了性能调优和生产环境实践经验。

qsc90123456的博客 546

grunt-concurrent实战教程:如何配置并发任务提升前端开发效率

**grunt-concurrent** 是一个强大的Grunt插件,专门用于并发运行多个Grunt任务,可以显著提升前端开发的工作流效率。通过并行执行编译、检查、监控等任务,您可以将构建时间减少30-50%,让开发过程更加流畅快速。🚀 ## 为什么需要并发任务管理? 在前端开发中,我们经常需要同时运行多个任务:编译Sass/CoffeeScript、代码检查、运行测试、文件监控等。传统的串

gitblog_00652的博客 370

基于大疆TSDK与Pix4D的热红外数据工程化处理:从RJPG到温度正射影像的完整工作流

本文详细介绍了基于大疆TSDK与Pix4D的热红外数据工程化处理完整工作流。通过Python脚本自动化解析RJPG格式的热红外图像,提取并转换其中的原始辐射数据为包含真实温度信息的TIFF文件,再结合Pix4Dmapper进行批量拼接,最终生成可直接用于GIS分析的温度正射影像图。该流程解决了手动处理效率低下、参数校准复杂等难题,实现了从原始数据到定量分析成果的高效、准确、可重复生产。

weixin_29161785的博客 375

手把手教你用Qt5打造二次元游戏启动器(附鸣潮同款UI源码)

本文详细介绍了如何使用Qt5框架从零开始构建一个功能完整、UI风格贴近《鸣潮》的二次元游戏启动器。教程涵盖无边框窗口、动态背景、自定义控件绘制、多线程资源加载以及下载管理等核心模块的实现,并提供了可运行的源码参考,帮助C++开发者和Qt爱好者深入掌握现代桌面应用开发技术。

weixin_29291863的博客 264

《Python实战进阶》No44: 并发框架:concurrent.futures 的使用(上)

在现代软件开发中,性能优化和高效的任务管理是不可或缺的技能。Python 提供了 `concurrent.futures` 模块,作为多线程和多进程编程的高级接口,极大地简化了并发任务的实现。本集将深入探讨 `ThreadPoolExecutor` 和 `ProcessPoolExecutor` 的用法,结合 Future 对象和回调机制,展示如何通过上下文管理器优雅地管理资源。同时,我们将通过两个实战案例——API 请求并发处理和矩阵运算并行化——来巩固所学知识,并讨论其在 AI 数据处理中的实际应用。

yweng18的博客 1934

关于LIO-SAM编译时出现错误 /usr/bin/ld: 找不到 -lBoost::timer

关于LIO-SAM编译时出现错误: 下载LIO-SAM代码 进入LIO-SAM文件夹,通过以下代码编译: mkdir build cd build cmake .. make 报错: /usr/bin/ld: 找不到 -lBoost::timer collect2: error: ld returned 1 exit status CMakeFiles/lio_sam_imuPreintegration.dir/build.make:759: recipe for target 'devel/lib/li

wwtx的博客 3648

实战Concurrent(1)

来自http://www.iteye.com/topic/363625   编写多线程的程序一直都是一件比较麻烦的事情,要考虑很多事情,处理不好还会出很多意想不到的麻烦。加上现在很多开发者接触到的项目都是打着企业级旗号的B/S项目,大多数人都很少涉及多线程,这又为本文的主角增加了一份神秘感。   讲到Java多线程,大多数人脑海中跳出来的是Thread、Runnable、synch...

玩一玩Java 140

RADIOML 2018.01A数据集在自动调制识别中的实战应用指南

本文提供了RADIOML 2018.01A数据集在自动调制识别(AMR)任务中的完整实战指南。内容涵盖从数据集介绍、数据获取与解包、高效预处理流程,到构建PyTorch数据管道、模型设计(如1D CNN、ResNet)以及训练调参策略。重点阐述了如何利用该数据集训练鲁棒的AI模型,以应对复杂信道环境和低信噪比挑战,并给出了详细的性能评估方法。

plant的博客 172

45.qt quick-qml虚拟软键盘详解(一)

1.qml虚拟键盘介绍 Qt虚拟键盘的主要功能包括: 可定制的键盘布局和风格与动态切换。 带有单词选择的预测性文本输入。 角色预览和替代角色视图。 自动大小写和空格插入。 不同分辨率的可伸缩性。 支持不同的字符集(拉丁,简体/繁体中文,印地语,日语,阿拉伯语,希伯来语,韩语和其他)。 支持大多数常见的输入语言,可以轻松扩展语言支持。 从左到右和从右到左的输入。 硬件键支持2路和5路导航。 手写支持,带有全屏输入的手势。 音频反馈。 跨平台功能。 支持多国语言,高达40多个语言 本

抵抗时间扭曲,坚持做一件有意义的事 3559

彻底告别页面卡顿:React Concurrent Mode异步更新革命实战指南

React Concurrent Mode是React过去2年重构Fiber架构的源动力,也是React未来的发展方向。它是一组React的新功能,可帮助应用保持响应,并根据用户的设备性能和网速进行适当的调整。从源码层面讲,Concurrent Mode是一套可控的“多优先级更新架构”,能够彻底改变React应用的性能表现。 ## 为什么需要Concurrent Mode?传统React更新的痛

gitblog_00432的博客 993

dify制作的工作流如何通过API调用

本文介绍了如何通过Python程序调用Dify工作流API实现数据处理功能。文章详细展示了workflow和chatflow的调用方法,包括参数设置和结果输出,并提供了一个完整的API调用工具代码示例。该工具可实现文本处理、成果查重、关键词生成等功能,支持通过Python脚本或Postman进行调用。核心代码包含API请求函数和批量处理函数,通过HTTP请求与Dify服务端交互,实现自动化数据处理流程。

hhue2007的专栏 933
上一篇: 从积木看项目
下一篇: 实战Concurrent
dingx
博客等级 码龄24年 67粉丝 112原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值