Grand Central Dispatch vs NSThreads?

时间:2012-02-11 05:42:01

标签: objective-c multithreading macos cocoa grand-central-dispatch

我搜索了各种来源,但并不真正理解使用NSThreads和GCD之间的区别。我是OS X平台的新手,所以我可能完全误解了这个。

从我在线阅读的内容来看,GCD似乎与基本线程(POSIX,NSThreads等完全相同),同时添加了更多技术术语(“块”)。它似乎只是使基本线程创建系统过于复杂(创建线程,运行函数)。

GCD究竟是什么?为什么它会优于传统的线程?应该何时使用传统线程而不是GCD?最后是否有GCD奇怪语法的原因? (“阻止”而不是简单地调用函数)。

我使用的是Mac OS X 10.6.8 Snow Leopard,我不是为iOS编程 - 我正在为Mac编程。我在Cocoa中使用Xcode 3.6.8,创建了一个GUI应用程序。

4 个答案:

答案 0 :(得分:46)

派遣的优势

调度的优势主要在这里概述:

Migrating Away from Threads

这个想法是你消除了你的工作,因为范式更容易适合MOST代码。

  
      
  • 它减少了应用程序为在应用程序的内存空间中存储线程堆栈而支付的内存损失。
  •   
  • 它消除了创建和配置线程所需的代码。
  •   
  • 它消除了管理和安排线程工作所需的代码。
  •   
  • 它简化了您必须编写的代码。
  •   

根据经验,使用GCD类型锁定代替@synchronized的速度大约快80%或更多,尽管微基准可能是欺骗性的。阅读更多here,虽然我认为与写入异步的建议在许多情况下并不适用,而且速度较慢(但它是异步的)。

主题的优点

为什么要继续使用线程?来自同一份文件:

  

重要的是要记住,队列不是万能的灵丹妙药   替换线程。提供的异步编程模型   队列适用于延迟不是问题的情况。   即使队列提供了配置执行优先级的方法   队列中的任务,更高的执行优先级不保证   在特定时间执行任务。因此,线程仍然是   在需要最小延迟的情况下更合适的选择   与音频和视频播放一样。

另一个我没有亲自找到使用队列的理想解决方案的地方是需要不断重新安排的守护进程。并不是说你不能重新安排它们,但在NSThread方法中循环更简单(我认为)。 编辑:现在我确信即使在这种情况下,GCD风格的锁定速度也会更快,您也可以在GCD调度操作中进行循环。

Objective-C中的块?

由于语法很糟糕,Objective-C中的块非常糟糕(尽管Xcode有时可以帮助自动完成,至少)。如果你看一下Ruby中的块(或其他任何语言),你会看到它们对于调度操作有多么简单和优雅。我会说你会习惯于Objective-C语法,但我真的认为你会习惯于从你的例子中复制很多东西:)

您可能会发现my examples from here有用,或者只是分散注意力。不确定。

答案 1 :(得分:11)

虽然到目前为止答案是关于单个应用程序域内线程与GCD的上下文以及它对编程的差异,但是你应该总是喜欢GCD的原因是因为多任务环境(因为你在MacOSX和不是iOS)。如果您的应用程序在您的计算机上单独运行 ,则线程可以正常运行。说,你有一个视频编辑程序,并希望对视频应用一些效果。在具有八个核心的机器上渲染需要10分钟。细

现在,当视频应用程序在后台搅拌时,您打开图像编辑程序并播放一些高分辨率图像,决定应用一些特殊的图像过滤器,您的图像应用程序聪明地检测到您有八个核心并启动八个线程来处理图像。好不是吗?除了表现糟糕。图像编辑应用程序对视频应用程序一无所知(反之亦然),因此两者都会请求它们各自的最佳线程数。当核心尝试从一个线程切换到另一个线程时会有痛苦和血液,因为为了避免饥饿,CPU最终会让所有线程都运行,即使在这种情况下,为视频运行仅4个线程也是更理想的应用程序和图像应用程序的4个线程。

有关更详细的参考,请查看http://deusty.blogspot.com/2010/11/introducing-gcd-based-cocoahttpserver.html,其中您可以看到使用GCD与线程的HTTP服务器的基准测试,并了解它如何扩展。一旦你理解了线程在多应用程序环境中对多核计算机的问题,你总是希望使用GCD,因为线程并不总是最优的,而GCD可能是因为操作系统可以根据负载扩展每个应用程序的线程使用量。

请记住,我们的机器很快就会有更多的GHz。从现在开始,我们只会有更多内核,所以你有责任在这个环境中使用最好的工具,那就是GCD。

答案 2 :(得分:9)

块允许传递一段代码来执行。一旦你超越了“奇怪的语法”,它们就会非常强大。

GCD还使用队列,如果在单独的队列中执行的代码被隔离,如果使用正确可以帮助解锁并发。这是一种提供背景和并发性的简单方法,同时最大限度地减少了死锁的可能性(如果使用的话)。

“奇怪的语法”是因为他们选择了插入符号(^),因为它是在C ++中作为运算符没有重载的少数符号之一

请参阅:   https://developer.apple.com/library/ios/#documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html

  

在为应用程序添加并发性时,调度队列   提供比线程更多的优点。最直接的优势是   工作队列编程模型的简单性。有了线程,你   必须为你想要执行的工作和为你的工作编写代码   创建和管理线程本身。派遣队列让   你专注于你真正想要执行的工作而不必   担心线程的创建和管理。相反,系统   为您处理所有线程创建和管理。该   优点是系统能够更多地管理线程   比任何单一的应用程序都有效。系统可以   根据可用的动态扩展线程数   资源和当前的系统条件。另外,系统是   通常能够比你更快地开始运行你的任务   你自己创建了这个帖子。

     

虽然您可能认为重写代码队列的代码会   很难,为调度队列编写代码通常更容易   而不是为线程编写代码。编写代码的关键是   设计自包含且能够运行的任务   异步。 (这对于线程和调度都是如此   队列。)

     

...

     

虽然你指出运行中的两个任务是正确的   串行队列不能同时运行,你必须记住,如果两个   线程同时获取锁定,并提供任何并发性   线程丢失或显着减少。更重要的是,   线程模型需要创建两个线程,这些线程占用   内核和用户空间内存。派遣队列不支付相同的费用   他们的线程的内存惩罚,以及他们使用的线程被保留   忙碌但没有阻止。

答案 3 :(得分:2)

GCD(Grand Central Dispatch):GCD提供并管理您的应用程序可以以块对象的形式提交任务的FIFO队列。提交到调度队列的工作在完全由系统管理的线程池上执行。不保证任务执行的线程。为什么GCD超过线程:

您的CPU核心正在做多少工作 你有多少CPU核心。 应该生成多少线程。 如果GCD需要它可以进入内核并与资源进行通信,从而更好地安排。 减少内核负载并更好地与OS同步 GCD使用线程池中的现有线程,而不是创建然后销毁。 系统硬件资源的最大优势,同时允许操作系统平衡当前运行的所有程序的负载以及加热和电池寿命等因素。

我与线程,操作系统和GCD AT [{3}}

分享了我的经验