`
lovnet
  • 浏览: 6824895 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
文章分类
社区版块
存档分类
最新评论

多核编程中的线程随机竞争模式的概率分析

阅读更多

多核编程中的线程随机竞争模式的概率分析
前一篇多核编程中的线程分组竞争模式中谈到了让线程分组竞争以解决多核CPU遇到的锁竞争导致的饥饿问题。
并不是任意的共享数据都能够设计成进行分组竞争的模式,比如最常用的需要用于查找的数据结构,当数据结构分成多个子数据结构后,每次查找时,不能指定查找某个特定的子数据结构,而必须进行二级查找,先在整个数据结构内找到对应的子数据结构(不加锁),然后再在子数据结构中查找(加锁)。如果同时多个线程进行查找,有可能查找的数据分布在不同的子数据结构里,也可能分布在同一子数据结构中。当查找分布在同一子数据结构时,这时就有可能发生锁竞争现象,从而引起CPU饥饿的发生。
在这种分布式数据结构的随机锁竞争中,需要知道的是在一个k个核的CPU上,需要的线程数m和划分的子数据结构个数n为多少时,才能保证至少有k个线程在同时运行的概率不低于给定的概率P。
首先m必须大于等于k,否则无法保证至少有k个任务在运行。子数据结构个数N也必须大于K,否则出现竞争的任务组数将少于k个,从而无法保证至少有k个任务在运行,当然n越大,任务出现竞争的概率就越小,同时运行的线程数量就越多,不妨设n大于等于m。在实际情况中,n并不是越大越好,当 n过大时,由于锁的数量和n相等,会导致锁占用过多的系统资源。
下面就来计算一下至少有k个线程在同时运行的概率,考虑一种最坏情况的假设:假设有两个线程在访问同一个子数据结构 ,那么它们一定会发生锁竞争。在这种最坏假设下,要保证至少有k个线程在同时运行 ,实际上相当于m个线程至少访问了k个不同的子数据结构。
假设访问每个子数据结构的线程数为Xi ( 0 <= Xi <= m, i∈{1,2,…n}),这样可以得到以下整数方程:
X1+X2+…+Xn = m (方程1)
要保证至少有k组线程在竞争,实际上相当于X1,X2…Xn中必须至少有k个大于0,这样至少有k个线程在运行的概率相当于上述方程满足,X2…Xn中必须至少有k个大于0的解的个数和所有可能解的个数的比值。
下面是对这个概率公式的一些实际计算结果:
当k=2(2核CPU), m=2(2个线程), P=(n-1) / (n+1) 当n=4时,P=0.6; 当n=8时,P=7/9 =0.7778;当n=16时,P=15/17=0.882
当k=2(2核CPU), m=4(4个线程), P=(n-1) (n+3)/ ((n+1)(n+2)) + 9 (n-1)/((n+3)(n+2)(n+1)) 当n=4时,P=0.83; 当n=8时,P=0.919;当n=16时,P=0.954
当k=4(4核CPU), m=4(4个线程), P=(n-1) (n-2)(n-3)/ ((n+1)(n+2)(n+3)) 当n=4时,P=0.0286; 当n=8时,P=0.212;当n=16时,P=0.47; 当n=32时,P=0.687
当k=4(4核CPU), m=6(6个线程), P = [ 1+12(n+15)/((n+4)(n+5)) ] ×[(n-1)(n-2)(n-3)]/ [(n+1)(n+2)(n+3)] 当n=8时,P=0.587;当n=16时,P=0.886; 当n=32时,P=0.978
从上面计算可以看出,当CPU核数固定时,线程数m越多,则概率愈大 ,子数据结构个数n越大,概率愈大。一般来说线程数最好比核数大一倍,这样得出的概率会大一些。
以上计算的是在最坏情况下的概率,实际情况中,由于两个线程在竞争同一个子数据结构时并不一定会发生竞争现象,因为可能发生线程A在进行锁操作时,线程B正在执行不需要加锁部分的代码,因此实际的概率会大于上面计算出的最坏情况下的概率。
分布式数据结构随机锁竞争和无锁编程的性能比较
在使用了随机锁竞争的分布式数据结构中,并行化的加速比期望值等于前面所计算出的概率×CPU核数,因此只要将概率保持大于一定的值,那么加速比是可以得到保证的,并且只要加大线程个数和子数据结构个数,那么加速比的期望值就会增加。另外分布式数据结构中相比于单线程的数据结构其操作要复杂一些,增加了一些计算开销,另外加上锁的计算开销,因此加速比要打一个较大的折扣。但是分布式数据结构的好处在于它的加速比系数不会随CPU核数的增加而降低,程序的性能是随着核数的增加而线形增加的(前提是在数据 结构中的元素个数足够多的情况下)。
在无锁编程中,由于使用了原子操作,原子操作是串行化的,虽然原子操作占的比重很小,但是这种串行化反映到加速比计算上需要按照阿姆尔达定律来计算,因此其性能同样不容乐观,会随着CPU核数的增加而降低。以一个无锁的FIFO队列为例,在进队操作时需要使用一条CAS原子操作,由于队列操作本身就很简单,因此昂贵的CAS操作所占的比例也不容小觑,在这种队列操作中,CAS所占的比例估计要达到20%左右(具体的数据需要通过测试才能确定),按照阿姆尔达定律,在一个8核的 CPU上的加速比系数将为3.33, 在一个64核CPU上,其加速比将小于5,当然这是只考虑队列操作没有考虑程序中其他并行操作的极端情况,但是不管怎么说,采用无锁编程的话,加速比系数会随CPU核数的增加而降低。
另外无锁编程相比于单线程编程,其代码也变复杂了,也增加了额外的计算开销,加速比也需要另外打一个折扣。
如果将分布式数据结构和单核时的多线程编程相比,则分布式数据结构中,仅仅增加了定位到子数据结构的开销,如果是查找类型的数据结构,子表的查找时间缩小了,实际上增加的开销小于定位子数据结构的开销。因此分布式数据结构增加的开销所占的比例是非常小的,其性能近似(略低)于单核时的多线程编程。
在CPU核数较少时,无锁编程的性能可能会优于分布式数据结构,并且优于单核多线程编程的性能,但是当CPU核数增加到一定程度时,分布式数据结构的性能优势就体现出来了。采用分布式数据结构可以复用部分单线程时的数据结构代码,采用加锁机制容易被程序员理解,并且实现的功能不受限制。而无锁编程则难度非常高,远非普通程序员所能掌握,并且实现的功能受到限制,比如实现一个无锁的队列,如果想要给队列加一个计数来掌握队列中有多少元素,采用无锁编程实现估计就很难行得通了,而这在有锁编程中只是一个简单得不能再简单的东西。因此对程序员来说,分布式数据结构是多核时代必需掌握的技术,而无锁编程也许可以用在某些无法使用分布式数据结构的特定场合。
需要说明的是前面对概率的计算隐含了一个前提,就是每个线程在访问各个子数据结构时的概率是相同的,这要求各个子数据结构必须是负载均衡的,否则如果访问各个子数据结构的概率不相同的话,计算出的结果会小于前面的计算结果,考虑一种最极端的情况,所有的数据都在一个子数据结构里,那么所有的线程都将竞争同一个子数据结构,那么问题倒退回多核编程中的锁竞争难题一文中描述一样的情况,这是一种可能比阿姆尔达定律更糟糕的情况。100%的负载均衡是做不到的,所幸可以通过一定的手段来使数据尽量变得均衡,使得数据能够相对较均匀地分布在各个子数据结构中,这样就不会对最终的概率产生较大影响。
参考资料:
[1]《并行编程模式》Timothy Mattson等著 敖富江译
[2]《多核程序设计技术》Shameem Akhter等著 李宝峰等译
[3]“An Optimistic Approach to Lock-Free FIFO Queues” Edya Ladan-Mozes and Nir Shavit
[4]《并行程序设计》 Barry Wilkinson, Michael Allen著,陆鑫达等译
[5]“Fast and lock-free concurrent priority queues for multi-thread systems” H. Sundell, Philippas Tsigas, Journal of Parallel and Distributed Computing. 2005
[6] NOBLE: A Non-Blocking Inter-Process Communication Library. H. SUNDELL, P. TSIGAS. Proceedings ofthe 6th Workshop on Languages, Compilers and Runtime Systems for Scalable omputers (LCR’02), Lecture Notes in Computer Science, Springer Verlag, 2002.
分享到:
评论

相关推荐

    多线程死锁,活锁,竞争锁问题总结

    - **随机化**:为每个线程分配一个随机延迟时间再尝试执行操作,减少同时尝试的概率。 - **优先级调整**:为线程设置不同的优先级,优先处理优先级高的线程。 - **引入外部干预**:通过外部机制中断或重新启动线程以...

    燕山大学多核程序设计实验报告.pdf

    线程同步是多线程编程中的关键,它避免了多个线程同时访问共享资源导致的数据不一致问题,通常有互斥量、信号量、事件等同步机制。 实验二则运用蒙特卡洛方法求解PI值。蒙特卡洛方法是一种基于概率统计的数值计算...

    pi_概率法圆周率_多线程_源码.rar

    标题中的“pi_概率法圆周率_多线程_源码.rar”表明这是一个关于计算圆周率(π)的程序,使用了概率方法,并且实现了多线程处理。源码通常指的是编程语言编写的未编译代码,可以提供给程序员进行学习、调试或修改。...

    并行计算_并行计算_多线程_

    需要注意的是,多线程编程涉及到同步和通信问题,如互斥锁、条件变量等,以避免数据竞争和死锁,确保程序正确性。 总的来说,通过并行计算和多线程技术,我们可以显著提高计算性能,尤其在需要大量计算的任务中,如...

    房间分配参赛代码

    描述中提到的“Intel线程竞赛”表明这是一个由Intel主办的编程竞赛,很可能强调多线程编程或并行计算。Intel经常举办这样的比赛来促进高性能计算和优化代码运行效率。在这种比赛中,参赛者需要利用多核处理器的特性...

    c__ 系统结构 操作系统 概率统计 离散数学

    4. **概率统计**:在计算机科学中,概率统计是分析和预测数据的重要工具,尤其在机器学习、数据分析和人工智能领域。基本概念包括概率论的基本定理、随机变量、期望值、方差、分布(如正态分布、泊松分布、二项分布...

    Random-Programs:实施随机主题的集合

    "Random-Programs" 是一个项目集合,专注于实现各种与...同时,也可以借鉴项目中的代码结构和设计模式,提高自己的编程技巧。对于想要扩展知识领域或者增强随机编程技能的人来说,"Random-Programs" 是一个宝贵的资源。

    基于C++14异步蒙特卡洛工具函数

    异步蒙特卡洛(Asynchronous Monte Carlo, AMC)是一种并行计算技术,它结合了蒙特卡洛方法和多线程编程,旨在提高计算效率,尤其在处理大规模模拟问题时。C++14标准引入了对并发和异步编程的支持,使得开发者能够更...

    Introduction_to_Algorithms_3rd_Edition.pdf

    值得注意的是,《算法导论》第三版新增了多线程方面的相关内容,反映了现代计算环境中并行和并发编程的重要性。这包括对多核处理器上算法设计和分析的新视角,以及对并行算法的介绍,使读者能够应对日益增长的并行...

    Miller-Rabin素数检测优化算法研究.pdf

    1. **多线程编程**:为了充分利用多核处理器的能力,论文中采用了多线程编程技术,使得算法可以在多个线程中并发执行,从而提高整体性能。 2. **异步编程模式**:通过采用异步编程模式,可以有效地避免在等待某些...

    并行计算课程设计(报告+代码+可执行文件)

    实验中创建了两个线程,通过多次测试,得出实验结果:由上面的理论加速比分析可知,当线程数为2时,理论加速比为2+log2=3.但由于实际操作中硬件设备以及内存分配的影响,实验加速比达不到理论值3.实验加速比在1.9...

    C++ 和面向对象的数值计算(pdg)

    面向对象编程(Object-Oriented Programming,简称OOP)是一种将现实世界中的问题抽象为类和对象的编程范式,它允许我们通过封装、继承和多态等概念来构建复杂的软件系统。在数值计算领域,C++的优势在于其高效性、...

    蚁群聚类算法的VC++程序

    尽管提供的压缩包文件名为"AntCluster单线程版",但在多核处理器的环境下,通过改进为多线程版本,可以同时运行多只蚂蚁,加快聚类速度,特别是在处理大规模数据集时。 总的来说,这个VC++实现的蚁群聚类算法程序...

    吉林大学计算机学院2015年春季期末考试安排

    5. **概率论与数理统计**:这门课为数据分析和机器学习提供基础,包括概率分布、假设检验、回归分析、随机过程等内容。 6. **嵌入式系统**:课程涵盖了嵌入式系统的硬件架构、操作系统、编程模型以及在各种应用中的...

    基于C++14异步蒙特卡洛工具函数.zip

    异步蒙特卡洛算法则将这种随机抽样过程与多线程或并发执行结合,以充分利用多核处理器的计算能力。在本项目中,我们可能会看到如何利用C++14的异步特性并行执行多个蒙特卡洛模拟,从而缩短总计算时间。 **C++14的...

    A Monte Carlo model_光子蒙特卡洛_MonteCarlo_蒙特卡洛_光子传输_蒙卡_源码.zip

    它通过随机抽样和概率统计方法来模拟物理过程,能够解决复杂光学系统中的问题,如光线追踪、光能分布、光谱分析等。下面我们将深入探讨这一主题。 首先,我们来看“蒙特卡洛”这个概念。蒙特卡洛方法源于20世纪40...

Global site tag (gtag.js) - Google Analytics