美文网首页
并发宏观、微观分析

并发宏观、微观分析

作者: Easy的幸福 | 来源:发表于2019-10-15 16:46 被阅读0次

    并发编程是一个复杂的技术领域,微观上涉及到原子性问题、可见性问题和有序性问题,宏观则表现为安全性、活跃性以及性能问题

    在设计并发程序的时候,主要是从宏观出发:

    • 安全性方面要注意数据竞争和竞态条件
    • 活跃性方面需要注意死锁、活锁、饥饿等问题
    安全性问题

    那什么是线程安全呢?其实本质上就是正确性,而正确性的含义就是程序按照我们期望的执行,并发Bug的三个主要源头:原子性问题、可见性问题和有序性问题

    所有的代码都需要认真分析一遍是否存在这三个问题呢?当然不是,其实只有一种情况需要:存在共享数据并且该数据会发生变化,通俗地讲就是有多个线程会同时读写同一数据

    数据竞争:

    当多个线程同时访问同一数据,并且至少有一个线程会写这个数据的时候,如果我们不采取防护措施,那么就会导致并发Bug

    竞态条件:

    指的是程序的执行结果依赖线程执行的顺序。eg: int count=0;count+=1,如果两个线程完全同时执行,那么结果是1;如果两个线程是前后执行,那么结果就是2,在并发条件下,线程的执行顺序是不确定的。
    也可以这么理解静竞态条件:

    if (状态变量 满足 执行条件) {
      执行操作
    }
    

    解决方案:用互斥这个技术方案,也就是锁。

    活跃性问题:

    死锁、活锁、饥饿

    • 活锁

    有时线程虽然没有发生阻塞,但仍然会存在执行不下去的情况,例如:现实世界里的例子,路人甲从左手边出门,路人乙从右手边进门,两人为了不相撞,互相谦让,路人甲让路走右手边,路人乙也让路走左手边,结果是两人又相撞了,一直谦让下去就是活锁的情况。

    解决方案:

    等待一个随机的时间再切换,Raft这样知名的分布式一致性算法中也用到了它

    • 饥饿

    线程因无法访问所需资源而无法执行下去的情况。在CPU繁忙的情况下,优先级低的线程得到执行的机会很小,就可能发生线程“饥饿”。(也就是一直获取不到锁)

    解决方案:

    有三种方案:一是保证资源充足,二是公平地分配资源,三就是避免持有锁的线程长时间执行,这三个方案中,方案一和方案三的适用场景比较有限,因为很多场景下,资源的稀缺性是没办法解决的,持有锁的线程执行的时间也很难缩短。倒是方案二的适用场景相对来说更多一些。

    使用公平锁,所谓公平锁,是一种先来后到的方案,线程的等待是有顺序的,排在等待队列前面的线程会优先获得资源。

    性能问题

    性能方面的度量指标有很多,三个指标非常重要,就是:吞吐量、延迟和并发量。

    • 吞吐量:指的是单位时间内能处理的请求数量。吞吐量越高,说明性能越好
    • 延迟:指的是从发出请求到收到响应的时间。延迟越小,说明性能越好
    • 并发量:指的是能同时处理的请求数量,一般来说随着并发量的增加、延迟也会增加。所以延迟这个指标,一般都会是基于并发量来说的。例如并发量是1000的时候,延迟是50毫秒。

    相关文章

      网友评论

          本文标题:并发宏观、微观分析

          本文链接:https://www.haomeiwen.com/subject/myismctx.html