写一个正确的并行程序要比写顺序执行程序困难。 其原因是并行程序中潜在的风险和错误的种类更多 —— 首先,在一个顺序执行程序中的错误同样会发生在并行程序中;其次,并行程序比顺序执行程序需要关注更多的风险,例如状态的竞争、数据的竞争、死锁、失效的信号以及活锁(livelock)。
同样测试并行程序要比测试顺序执行程序困难。首先,测试并行程序的程序本身就是并行程序;其次,并行程序的错误更难预测和重现。在顺序执行程序中的错误具有确定性。在给定的输入和初始状态下,一个顺序执行程序出错了,那么每次它都会出错,在相同条件下。而一个并行程序出错了,则有可能是一些不确定因素导致的。
由于这点,重现并行程序的错误变得非常困难。不仅错误是随机的,而且现象可能也不确定,甚至在同样的环境下测试也可能不发生错误,也就是说在客户那里每天都发生的错误可能在你的测试实验室中就不会发生。进一步说,试图调试和监控并行程序会引入时间片(timing)和同步的概念,这也有可能阻止错误的发生。在海森堡不确定理论(Heisenberg's uncertainty principle)中,观察一个系统的状态往往会改变它。
所以,基于以上这些令人沮丧的消息,我们应该如何保证并行程序可以正常工作呢?我们使用和其他工程学同样的方法来管理并行程序测试的复杂性 —— 尽量可能地隔离这个复杂性。
构造限制并行交互的程序
我们可以在程序中全部使用公有的和静态的变量。提醒你,这不是一个好主意,但是它确实可行 —— 只是这样做更困难并且程序更脆弱。通过封装,我们可以不必关心所有程序代码就可以分析某部分程序的行为。
同样地,通过把并行交互(concurrent interactions)封装在几个地方,例如,工作流管理器、资源池、工作队列、以及其他的并行对象中。这样会使得分析和测试并行程序变得更简单。一旦并行交互被封装后,你就可以集中精力测试并行机制其自身而不被其他错误所困扰。
并行机制,例如共享的工作队列,经常被作为从一个线程到另一个线程的管道。这些机制中,通常包含了必要的同步机制来保证其中数据的完整性 —— 但是被传入和传出的对象属于应用程序而非工作队列,所以应用程序就有责任负责这些对象的线程安全。你可以使这些对象成为线程安全的(最简单的办法就是使它们不可变(immutable)同时这也是最可靠的办法),但是另一个说法是:使这种不可变性更有效。
有效的不可变的对象(effectively immutable object)是说,这种对象在设计的时候并非不可变的 —— 它们可以具有可变的状态 —— 但是当其他线程访问这样的对象的时候,程序通常认为它们是不可变的。 换句话说,一旦你把一个可变的对象放入一个共享的数据结构中,此时这个对象可以被其他线程所访问时,确保这个对象不会被其他线程重复修改。通过限制主要几个类的可变性(mutability)可以限制潜在的不正确的并行行为的范围。
代码(1)是如何有效地利用不变性(immutability)来大大简化测试的例子。 客户端代码向工作管理器(work manager)提交一个求最大公倍数的请求,计算程序(calculation)被表示为Callable<BigInteger[]>,执行者(Executor)返回一个Future<BigInteger[]>表示计算程序。客户端代码等待Future计算结果。
FactorTask这个类是不可变的,因此是线程安全的,无需额外的并行交互的测试。但是FactorTask返回一个数组,这个数组是可变的。线程间共享可变状态需要进行同步处理,但是由于应用程序代码的结构,因此一旦这个BigInteger的数组被FactorTask返回,它的内容应该是总是不变的,由此,客户端的代码可以在Executor框架中使用"piggyback"技术来隐式地(implicit)进行同步,这样的话,在访问这个数组的时候就无需额外的同步机制。
ExecutorService exec
=
class
FactorTask
implements
Callable
<
BigInteger[]
>
{
private
final
BigInteger number;
public
FactorTask(BigInteger number) {
this
.number
=
number;
}
public
BigInteger[] call()
throws
Exception {
return
factorNumber(number);
}
}
Future
<
BigInteger[]
>
future
=
exec.submit(
new
FactorTask(number));
//
do some stuff
BigInteger[] factors
=
future.get();
这项技术几乎可以被整合到所有的并行机制中,包括Executor, BlockingQueue, 以及ConcurrentMap。 通过把有效的不可变的对象(effectively immutable object)传递进去然后通过callback得到返回的有效的不可变的对象(effectively immutable object),利用这种方法你可以避免许多创建和测试线程安全类的复杂性。
测试并行的“积木”
一旦你把并行交互隔离到一些组件(component)中,你就可以集中精力测试这些组件。由于测试并行代码非常困难,所以你应该花费比测试顺序执行代码更多的时间来测试它。
以下的一些因素是测试并行类的一些最佳实践。
※ 测试是不稳定的 —— 你应该测试更长时间。
※ 测试更多种状态 —— 只是一遍一遍的测试相同的输入和初始状态是没有用的,你应该测试不同的输入数据。
※ 测试更多的交互 —— 通过调整数据输入的时间使线程之间的交互达到不同状态。
※ 增加线程数量 —— 如果线程数量太少可能测试结果也没有什么意义,更多的线程将会造成更多的冲突。
※ 避免引入同步机制 —— 如果在测试程序中引入同步机制,将会影响到并行程序测试的结果。
所有这些听起来就像是一大堆工作要做,而事实也确实如此。但是通过使用一些被广泛应用而且经过充分测试的组件,我们可以大大减少测试并行程序的工作量。而且通过重用已知的组件库,譬如java.util.concurrent包,你可以进一步地减少测试的负担。
---
原文:http://www.theserverside.com/tt/articles/article.tss?l=TestingConcurrent
分享到:
相关推荐
华中科技大学博士论文,对并行测试的多种技术进行分析,条例清晰,便于大家理解和掌握。
《基于占优度的消息传递并行程序变异体约简方法》是针对并行程序测试与优化的一个重要研究领域。在并行程序设计中,由于其复杂性和多样性,常常会产生多种变异体,这些变异体可能在功能上有所差异,或者在性能上有...
"并行程序测试的关键技术研究"可能涵盖如何在多线程或多进程环境中应用程序切片。并行程序的测试更具挑战性,因为需要考虑并发和同步问题。切片技术可能用于识别并行执行的不同线程或进程间的关键交互,以生成有效的...
#### 四、并行程序调试与测试 并行程序的调试是一个复杂的过程,涉及到定位错误、分析性能瓶颈和验证并行一致性。有效的调试策略包括使用专门的并行调试工具、逐步增加并行度进行测试以及进行基准性能对比。 #### ...
Based Environment for Test,ABBET),该标准将测试系统划分为五个层次:产品描述层、测试需求/策略层、测试程序层、资源管理层和仪器控制层。 并行自动测试系统在核心测试过程上继承了串行自动测试系统的基本特性...
并行程序串行化执行是计算机科学中一个重要的概念,特别是在多核处理器和分布式系统中。这个主题主要涉及如何将原本设计为并行运行的任务转换为串行执行,以适应某些特定场景的需求或解决特定问题。CGLIB(Code ...
中国科学院的博士论文。研究的很深入,并对应开发了一种并行编程软件。
分布式并行程序设计是计算机科学领域的一个重要主题,它涉及到如何在多台计算机之间协调工作,以解决大规模计算问题。东北大学的这门课程显然旨在为初学者提供基础理论和实践经验,帮助他们理解和掌握这一技术。以下...
《并行程序设计实践》课程是在计算机科学与技术领域中一门重要的实践课程,它不仅要求学生掌握理论知识,更强调通过实践掌握并行编程的核心技术。该课程以当前高性能计算领域广泛应用的MPI、OpenMP和CUDA工具为教学...
STM32单片机LCD12864并行程序是一个专为STM32微控制器设计的项目,用于驱动128x64像素分辨率的LCD显示器,采用并行接口进行数据传输。在这个程序中,STM32通过并行接口与LCD12864模块通信,控制其显示内容。这种并行...
串口并行测试程序是一种专为测试多个串行通信接口设计的应用软件,它允许用户同时对多个串口进行通讯测试,以确保设备之间的数据传输准确无误。在现代电子设备和自动化系统中,串口通信仍然是连接不同硬件设备的重要...
最小集合覆盖MPI并行程序,C++语言编写,程序运行效率较高,加速比良好,里面测试了三组集合。很容易改为串行程序
并行程序设计环境与工具 并行程序设计环境与工具是高性能计算的核心组件,旨在提供一个强大且灵活的平台,以支持高性能计算应用程序的开发、调试和优化。该环境包括软件工具与环境、并行编译器、并行程序调试、并行...
【12864并行测试程序】是一个专为51单片机设计的C语言程序,主要用于教育和实验目的,特别适合初学者理解和掌握单片机编程以及12864液晶显示屏的并行接口操作。这个程序的核心是通过并行方式与12864液晶显示屏进行...
mpi/omp 并行测试程序(fortran)编写的,已经在单机和工作站测试过