并发主题

什么使得并行编程变得很难?

有些工作很容易进行并行化,例如,如果需要一个人8小时,画一个房间,然后两个人可以在四个小时并行画。同样的,两个软件线程可以从彩色图片转换为灰度图片比一个线程工作快两倍。注:属于这一类的程序已经被并行化,例如,科学计算工作量,图形,Photoshop,甚至是开放源码的应用程序像ImageMagick等。

也有其他程序在本质上是连续的顺序的,例如,两个家伙烹饪会不会比一个人快2倍?因为任务不完全可以被并行化:有任务间的依赖关系的烹饪流程,两个厨师中一个要等待对方完成。不幸的是,很多程序都有人工任务间的依赖关系,因为程序员写他们有自己的思维定势。

例如下面代码:

macroclock_output_data mb; //Global variable
for (...) // The OUTER loop
   decode_slice(...);
   if(mb->last_mb_in_slice)
       break;

void decode_slice(...)
    ...
    mb = ...

mb被声明为一个全局变量,可能是避免其重复的分配和释放。这是一个合理的ST优化。从MT多核角度来看,outer loop循环迭代有相互之间的依赖关系,它们不能被并行运行。

调试多线程代码为什么难?

调试多线程代码是非常困难的,因为错误随机显示。

考虑两个线程进行增加值:

X = X + 1
汇编代码如下
T0 T1
A Load X , R0 D Load A, R0
B Increment R0 E Increment R0
C Store R0, X F Store R0, A

程序员希望X到两个线程都完成后递增2。然而,当线程同时运行,他们的运行可以以任何顺序交错。 X的值取决于最终的交织(假设X为0之前,两个线程试图递增)。

例如出现下面三个顺序:

ABCDEF: X = 2 (正确)
DEAFBC: X=1 (不正确)
ADBCEF: X = 1 (不正确)

这里有一个依赖,D应不在C执行之前执行(或A应该没有发生在F之前)。程序员忽视了这种依赖性。然而,代码不精细化就不可能让跟踪bug或测试修复工作事半而功倍。此外,传统的如printf和gdb调试技巧变得毫无用处,因为他们扰乱系统,从而改变代码的行为,很多时候掩盖错误。

什么是性能优化的重要挑战?

并行程序经常慢于串行程序,原因有两个:

  1. 有太多的依赖关系(真实的或人工的):程序员经常反复删除依赖,有时甚至重新编写整个程序,以减少这些依赖。
  2. 争用的硬件资源:如果争用一些硬件资源线程将变成串行化,如共享缓存。程序员识别和减少这一论点。注意确定这些瓶颈,尤其是具有挑战性的,因为硬件性能计数器是不可靠的。

 

 

java多线程

Java同步或锁

Java性能调优