并发和同步执行

时间:2013-10-04 14:51:34

标签: ios multithreading concurrency grand-central-dispatch

我正在阅读OReilly的 iOS6编程手册,我对此感到困惑。引用第378页,第6章“并发”:

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

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

这是正确的还是它如何运作?

4 个答案:

答案 0 :(得分:4)

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

  

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

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

  

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

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

  

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

不。不对。同样,它们混合了同步/异步和串行/并发。我怀疑他们想要说的是:当你异步地排队一个块时,你自己的程序总是会立即继续,而不必等待队列执行代码。

  

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

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

总的来说,整个段落非常可怕且具有误导性。

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

答案 1 :(得分:3)

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

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

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

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

答案 2 :(得分: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

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

答案 3 :(得分:0)

  

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

我发现它令人困惑,而我能想到的唯一解释是,她正在谈论是谁阻止了谁。来自man dispatch_sync

  

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

因此执行会立即返回到您的代码,但是dispatch_sync在排队块之后所做的下一步是等待信号量,直到执行该块为止。您的代码阻止因为它选择了。

代码阻塞的另一种方式是当队列选择使用您的线程(执行dispatch_sync的那个)运行块时。在这种情况下,您的代码将无法恢复控制,直到执行该块为止,因此对信号量的检查将始终发现该块已完成。

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