Grand Central Dispatch vs NSThreads?

fdh*_*fdh 30 macos cocoa multithreading objective-c 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应用程序.

Dan*_*ark 49

调度的优点

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

迁移远离线程

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

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

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

线程的优点

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

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

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

Objective-C中的块?

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

你可能会发现我在这里的例子很有帮助,或者只是分散注意力.不确定.


Grz*_*icz 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.


bry*_*mac 9

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

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

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

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

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

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

...

虽然您指出在串行队列中运行的两个任务不会同时运行是正确的,但您必须记住,如果两个线程同时进行锁定,则线程提供的任何并发都将丢失或显着减少.更重要的是,线程模型需要创建两个线程,这两个线程占用内核和用户空间内存.调度队列不会为其线程支付相同的内存损失,并且它们使用的线程会保持忙碌而不会被阻塞.