2

我正在阅读 OReilly 的iOS6 Programming Cookbook并且对某些事情感到困惑。引自第 378 页,第 6 章“并发”:

对于任何不涉及 UI 的任务,您都可以在 GCD 中使用全局并发队列。这些允许同步或异步执行。但是同步执行并不意味着您的程序要等待代码完成才能继续。它只是意味着并发队列将等到您的任务完成,然后再继续队列中的下一个代码块。当您将块对象放在并发队列上时,您自己的程序总是会立即继续运行,而无需等待队列执行代码。这是因为并发队列,顾名思义,在主线程以外的线程上运行它们的代码。

我将引起我兴趣的文字加粗。我认为这是错误的,因为正如我今天刚刚了解到的,同步执行意味着程序在继续之前等待代码完成。

这是正确的还是它是如何真正起作用的?

4

4 回答 4

4

这一段怎么错了?让我们数一下方法:

对于任何不涉及 UI 的任务,您都可以在 GCD 中使用全局并发队列。

这是过于具体和不准确的。某些以 UI 为中心的任务,例如加载图像,可以在主线程之外完成。最好将其表述为“在大多数情况下,除了主线程之外,不要与UIKit类交互”,但也有例外(例如,UIGraphicsContext从 iOS 4、IIRC 开始,绘制到 a 是线程安全的,而绘制是 a CPU 密集型任务的一个很好的例子,可以卸载到后台线程。)FWIW,任何你可以提交到全局并发队列的工作单元,你也可以提交到私有并发队列。

这些允许同步或异步执行。但是同步执行并不意味着您的程序要等待代码完成才能继续。它只是意味着并发队列将等到您的任务完成,然后再继续队列中的下一个代码块。

正如 iWasRobbed 推测的那样,他们似乎将同步/异步工作提交与串行/并发队列混为一谈。根据定义,同步执行确实意味着您的程序在继续之前等待代码返回。根据定义,异步执行意味着您的程序不等待。类似地,串行队列一次只执行一个提交的工作单元,按 FIFO 顺序执行。并发队列,私有的或全局的,在一般情况下(在一秒钟内更多),按照它们入队的顺序,在一个或多个后台线程上调度提交的块以执行。使用的后台线程数是一个不透明的实现细节。

当您将块对象放在并发队列上时,您自己的程序总是会立即继续运行,而无需等待队列执行代码。

没有。不对。同样,他们混淆了同步/异步和串行/并发。我怀疑他们想说的是:当您将一个块异步排队时,您自己的程序总是会立即继续运行,而无需等待队列执行代码。

这是因为并发队列,顾名思义,在主线程以外的线程上运行它们的代码。

这也是不正确的。例如,如果你有一个私有并发队列,你用它作为读/写锁来保护一些可变状态,如果你dispatch_sync从主线程到那个队列,你的代码在很多情况下会在主线程上执行线程

总的来说,整个段落真的非常可怕和误导。

编辑:我在对另一个答案的评论中提到了这一点,但为了清楚起见,把它放在这里可能会有所帮助。“同步与异步调度”的概念和“串行与并发队列”的概念在很大程度上是正交的。您可以以同步或异步方式将工作分派到任何队列(串行或并发)。同步/异步二分法主要与“dispatch* er *”相关(因为它确定调度程序是否在块完成之前被阻塞),而串行/并发二分法主要与 dispatch* ee *相关块(因为它确定调度程序是否可能与其他块同时执行)。

于 2013-10-04T16:09:15.543 回答
3

我认为那段文字写得不好,但它们基本上解释了在串行队列上执行与在并发队列上执行之间的区别。串行队列在一个线程上运行,因此它别无选择,只能一次执行一项任务,而并发队列可以使用一个或多个线程。

串行队列按照放入队列的顺序依次执行下一个任务。每个任务都必须等待前一个任务被执行,然后才能执行(即同步)。

在并发队列中,任务可以与其他任务同时运行,因为它们通常使用多个线程(即异步),但是它们仍然按照它们入队的顺序执行,并且它们可以有效地在任何命令。如果使用NSOperation,还可以在并发队列上设置依赖关系,以确保某些任务在其他任务之前执行。

更多信息: https ://developer.apple.com/library/ios/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html

于 2013-10-04T15:24:54.333 回答
1

作者是Vandad Nahavandipoor,我不想影响这家伙的销售收入,但他所有的书在并发章节中都包含相同的错误:

http://www.amazon.com/Vandad-Nahavandipoor/e/B004JNSV7I/ref=sr_tc_2_rm?qid=1381231858&sr=8-2-ent

这很讽刺,因为他有一本 50 页的书正是关于这个主题的。

http://www.amazon.com/Concurrent-Programming-Mac-iOS-Performance/dp/1449305636/ref=la_B004JNSV7I_1_6?s=books&ie=UTF8&qid=1381232139&sr=1-6

人们应该停止阅读这个人的书。

于 2013-10-08T11:50:54.097 回答
0

当您将块对象放在并发队列上时,您自己的程序总是会立即继续运行,而无需等待队列执行代码。这是因为并发队列,顾名思义,在主线程以外的线程上运行它们的代码。

我觉得这很混乱,我能想到的唯一解释是,她在谈论谁阻止了谁。来自man dispatch_sync

从概念上讲,dispatch_sync() 是一个方便的 dispatch_async() 包装器,它添加了一个信号量来等待块的完成,以及一个包装器来表示它的完成。

因此,执行会立即返回到您的代码,但是在将块排队之后要做的下一件事dispatch_sync是等待信号量,直到块被执行。您的代码会阻塞,因为它选择这样做。

您的代码阻塞的另一种方式是当队列选择使用您的线程(执行 dispatch_sync 的线程)运行一个块时。在这种情况下,您的代码在块执行之前不会恢复控制,因此对信号量的检查总是会发现块已完成。

Erica Sadun 肯定比我更了解,所以也许我在这里遗漏了一些细微差别,但这是我的理解。

于 2013-10-04T16:06:35.007 回答