pthreads是否比GCD有任何优势?

时间:2010-01-27 04:47:34

标签: multithreading pthreads grand-central-dispatch

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

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

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

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

6 个答案:

答案 0 :(得分:15)

我来自另一个方向:在我的应用程序中开始使用pthreads,我最近用C ++ 11&{39}替换了std::thread。现在,我正在使用更高级别的构造,如pseudo-boost threadpool,甚至更抽象的英特尔Threading Building Blocks。我认为GCD应该达到甚至高于TBB。

一些评论:

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

所以,让我们分解可能的实现:

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

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

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

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

答案 1 :(得分:14)

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

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

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

答案 2 :(得分:4)

GCD是Apple技术,并不是最兼容的跨平台; pthread几乎可以在OSX,Linux,Unix,Windows上使用..包括这个toaster

GCD针对线程池并行性进行了优化。 Pthreads(如你所说)是非常复杂的并行构建块,你可以开发自己的模型。如果您有兴趣了解有关pthreads和不同并行模型的更多信息,我强烈建议您选择一本关于该主题的书。

答案 3 :(得分:3)

任何声明/辅助方法如openmpIntel TBB GCD都应该非常擅长embarrassingly parallel问题,并且可能很容易击败天真的手动pthread-ed并行排序。我建议你仍然学习pthreads。您将更好地理解并发性,您将能够在每种特定情况下应用正确的工具,如果没有其他任何东西 - 那里有大量基于pthread的代码 - 您将能够读取“遗留”代码。 / p>

答案 4 :(得分:0)

通常:每个Pthread实现1个任务使用互斥锁(操作系统功能)。
GCD:   每个块1个任务,分组为队列。每个虚拟CPU 1个线程可以获得队列,并且在没有互斥锁的情况下运行所有​​任务。这减少了线程管理开销和互斥开销,这应该会提高性能。

答案 5 :(得分:0)

GCD抽象线程并为您提供调度队列。它在考虑可用处理器核心数量的情况下创建必要的线程。 GCD是开源的,可通过libdispatch库获得。 FreeBSD自8.1起包含libdispatch。 GCD和C Blocks是Apple向C编程社区提供的市长贡献。我永远不会使用任何不支持GCD的操作系统。