1.1 同步和异步 首先这里说的同步和异步是指函数/方法调用方面。 很明显,同步调用会等待方法的返回,异步调用会瞬间返回,但是异步调用瞬间返回并不代表你的任务就完成了,他会在后台起个线程继续进行任务。 1.2 并发和并行 并发和并行在外在表象来说,是差不多的。由图所示,并行则是两个任务同时进行,而并发呢,则是CPU在多个任务间的切换执行,一会做任务1,一会又切换做任务2。单个cpu是不能做并行的,只能通过CPU时钟片的切换做并发。 1.3 临界区 临界区用来表示一种公共资源或者说是共享数据,可以被多个线程使用,但是每一次,只能有一个线程使用它,一旦临界区资源被占用,其他线程要想使用这个资源,就必须等待。 ![]() 1.4 阻塞和非阻塞 阻塞和非阻塞通常形容多线程间的相互影响。比如一个线程占用了临界区资源,那么其它所有需要这个资源的线程就必须在这个临界区中进行等待,等待会导致线程挂起。这种情况就是阻塞。此时,如果占用资源的线程一直不愿意释放资源,那么其它所有阻塞在这个临界区上的线程都不能工作。 非阻塞允许多个线程同时进入临界区。 所以阻塞的方式,一般性能不会太好。根据一般的统计,如果一个线程在操作系统层面被挂起,做了上下文切换了,通常情况需要8W个时间周期来做这个事情。
1.5 死锁、饥饿、活锁 所谓死锁:是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。就如同下图中的车都想前进,却谁都无法前进。 但是死锁虽说是不好的现象,但是它是一个静态的问题,一旦发生死锁,进程被卡死,cpu占有率也是0,它不会占用cpu,它会被调出去。相对来说还是比较好发现和分析的。 与死锁相对应的是活锁。活锁,指事物1可以使用资源,但它让其他事物先使用资源;事物2可以使用资源,但它也让其他事物先使用资源,于是两者一直谦让,都无法使用资源。 举个例子,就如同你在街上遇到个人,刚好他朝着你的反方向走,与你正面碰到,你们都想让彼此过去。你往左边移,他也往左边移,两人还是无法过去。这时你往右边移,他也往右边移,如此循环下去。 一个线程在取得了一个资源时,发现其他线程也想到这个资源,因为没有得到所有的资源,为了避免死锁把自己持有的资源都放弃掉。如果另外一个线程也做了同样的事情,他们需要相同的资源,比如A持有a资源,B持有b资源,放弃了资源以后,A又获得了b资源,B又获得了a资源,如此反复,则发生了活锁。活锁会比死锁更难发现,因为活锁是一个动态的过程。 饥饿是指某一个或者多个线程因为种种原因无法获得所需要的资源,导致一直无法执行。 2.1 Amdahl定律 定义了串行系统并行化后的加速比的计算公式和理论上限 加速比定义:加速比=优化前系统耗时/优化后系统耗时 举个例子: 加速比=优化前系统耗时/优化后系统耗时=500/400=1.25 这个定理表明:增加CPU处理器的数量并不一定能起到有效的作用,提高系统内可并行化的模块比重,合理增加并行处理器数量,才能以最小的投入,得到最大的加速比。 2.2 Gustafson定律 说明处理器个数,串行比例和加速比之间的关系 则加速比=n-F(n-1) //推导过程略 只要有足够的并行化,那么加速比和CPU个数成正比 |