pthreads是否比GCD有任何优势?

Mik*_*ike 19 multithreading pthreads grand-central-dispatch

在最近学习了Grand Central Dispatch之后,我发现多线程代码非常直观(使用GCD).我喜欢这样一个事实,即不需要锁(事实上它在内部使用无锁数据结构),并且API非常简单.

现在,我开始学习pthreads,我不禁对复杂性感到不知所措.线程连接,互斥体,条件变量 - 所有这些事情在GCD中都不是必需的,但在pthreads中有很多API调用.

pthreads是否比GCD有任何优势?它效率更高吗?是否存在正常使用情况,其中pthreads可以执行GCD无法执行的操作(不包括内核级软件)?

在跨平台兼容性方面,我并不太关心.毕竟,libdispatch是开源的,Apple已经将其关闭更改作为GCC的补丁,clang支持关闭,并且已经(从FreeBSD开始),我们开始看到一些非Apple的GCD实现.我最感兴趣的是使用API​​(具体的例子会很棒!).

kfm*_*e04 15

我来自另一个方向:开始pthreads在我的应用程序中使用,我最近用C++ 11代替了它std::thread.现在,我正在使用更高级别的构造,如伪升级线程池,甚至更抽象的英特尔线程构建模块.我认为GCD应该达到甚至高于TBB.

一些评论:

  • imho,pthread 并不比GCD 复杂:在其基本核心,pthread实际上只包含很少的命令(只需少量命令:只使用OP中提到的命令将为您提供95%以上的功能).像任何低级库一样,它是你如何将它们组合在一起以及如何使用它来为你提供它的力量.不要忘记最终像GCD和TBB这样的库会像pthreads或那样调用一个线程库std::thread.
  • 有时,它不是你使用的,而是你如何使用它,它决定了成功与失败.作为图书馆的支持者,TBB或GCD将告诉您使用他们的库的所有好处,但是直到您在真实的应用程序环境中尝试它们,所有这些都具有理论上的好处.例如,当我读到使用细粒度parallel_for是多么容易时,我立即在一个我认为可以从并行性中受益的任务中使用它.当然,我也被TBB处理有关最佳加载平衡和线程分配的所有细节这一事实所吸引.结果? TBB比单线程版本长五倍! 但我不怪TBB:回想起来,这显然是滥用parallel_for的情况:当我读到精细打印时,我发现了使用parallel_for所涉及的开销,并假设在我的情况下,上下文的成本 - 切换和添加的函数调用超过了使用多个线程的好处.因此,您必须对案例进行分析,以确定哪个案例运行得更快.您可能必须重新组织算法以减少线程开销.
  • 为什么会这样?pthread或没有线程如何比GCD或TBB更快?当设计师设计GCD或TBB时,他必须对任务运行的环境做出假设.事实上,该库必须足够通用,以便它可以处理开发人员的奇怪,不可预见的用例.这些一般实现不会免费提供.在正面,库将查询硬件和当前运行环境以更好地进行负载平衡.这会对你有利吗?要知道的唯一方法就是尝试一下.
  • 学习低级库有什么好处,比如有std::thread更高级别的库可用吗?答案是肯定的.使用更高级别库的优点是,从实现细节中抽象出来.使用更高级库的缺点还在于从实现细节中抽象出来.在使用时pthreads,我非常了解对象的共享状态和生命周期,因为如果我放松警惕,特别是在中型到大型项目中,我很容易就会遇到竞争条件或内存故障.当我使用更高级别的库时,这些问题会消失吗?并不是的.看起来我不需要考虑它们,但事实上,如果我对这些细节感到邋,那么库的实现也会崩溃.因此,您会发现,如果您了解较低级别的构造,那么所有这些库实际上都是有意义的,因为在某些时候,如果您使用较低级别的调用,您将考虑自己实现它们.当然,在这一点上,通常最好使用经过时间考验和调试的库调用.

那么,让我们分解可能的实现:

  • TBB/GCD库调用:最大的好处是初学者的线程.与学习低级图书馆相比,他们的入学门槛较低.但是,它们也忽略/隐藏了使用多线程的一些陷阱.动态负载平衡将使您的应用程序更加便携,无需您进行额外编码.
  • pthread和std::thread调用:实际上很少有人学习,但要正确使用它们需要注意细节并深入了解应用程序的工作方式.如果你能理解这个级别的线程,那么更高级库的API肯定会更有意义.
  • 单线程算法:让我们不要忘记简单的单线程段的好处.对于大多数应用程序而言,单线程比多线程更容易理解,更不容易出错.事实上,在许多情况下,它可能是适当的设计选择.事实上,一个真正的应用程序经历了各种多线程阶段和单线程阶段:可能不需要一直是多线程的.

哪一个最快? 令人惊讶的事实是,它可能是上述三种中的任何一种.要获得多线程的速度优势,您可能需要彻底重新组织算法.利益是否超过成本是高度依赖于案例的.

哦,OP询问了thread_pool不合适的情况.简单的情况:如果你有一个紧密的循环,每个循环不需要很多循环来计算,使用thread_pool可能比没有严重重做的好处花费更多.还要注意函数调用的开销,例如通过线程池的lambda与使用单个紧密循环.

对于大多数应用程序,多线程是一种优化,所以在正确的时间和地点进行.


sle*_*man 14

那种压倒性的感觉,你正在经历......这正是GCD被发明的原因.

在最基本的层面上有线程,pthreads是线程的POSIX API,因此您可以在任何兼容的操作系统中编写代码并期望它能够工作.GCD建立在线程之上(虽然我不确定它们是否真的使用pthread作为API).我相信GCD只能在OS X和iOS上运行 - 简而言之就是它的主要缺点.

请注意,大量使用线程并需要高性能的项目会实现自己的线程池版本.GCD允许您无数次地避免(重新)发明轮子.

  • 实际上,速度是GCD优于使用pthreads的优势之一.即使像Apache这样的pthreads中复杂的自实现线程池也很少像GCD一样好,因为GCD对操作系统和底层硬件有更好的了解. (4认同)
  • @slebetman:一旦创建了线程,操作系统会将它们视为与任何其他线程相同,那么创建它们的库并不重要.因此,GCD和Pthreads一旦创建,将以完全相同的速度运行.现在,如果GCD实现了它自己的互斥锁,那么它们可能比手动pthread互斥锁更快或更慢(它主要取决于编程).GCD管理线程创建和取消自身,因此它可能会也可能不会提供最佳解决方案; pthreads也是如此,除了程序员负责使用pthreads创建/取消,并且可以潜在地优化应用程序. (4认同)
  • 根据Apple的文档,GCD的真正优势在于"管理".手动调整和优化线程池非常困难.GCD做到了.Apple的GCD实现与内核集成,而不是在pthreads之上. (3认同)