【问题标题】:Concurrency and synchronous execution并发和同步执行
【发布时间】:2013-10-04 14:51:33
【问题描述】:

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

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

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

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

【问题讨论】:

    标签: ios multithreading concurrency grand-central-dispatch


    【解决方案1】:

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

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

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

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

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

    当你把一个块对象放到一个并发队列上时,你自己的程序 总是立即继续而不等待队列执行 代码。

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

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

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

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

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

    【讨论】:

    • 非常感谢,我绞尽脑汁才明白一章从一开始就大错特错。我想我现在需要再找一本书。
    【解决方案2】:

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

    串行队列按照它们被放入队列的顺序在下一个任务之后执行。每个任务都必须等待前一个任务执行完毕才能执行(即同步)。

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

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

    【讨论】:

    • 更准确地说,在并发队列中,任务仍以 FIFO/入队顺序开始,但它们可以有效地完成以任何顺序,取决于许多因素。
    • 我同意;这是一个非常糟糕的段落,充满了事实的不准确之处。
    • iWasRobbed,谢谢你的回答;这里的问题是我试图理解同步和异步调度之间的区别,因为这本书是我正在阅读的第一本 iOS 书,所以我很困惑;然后我在堆栈溢出时来到这里,人们向我解释说,同步调度并不意味着任务将在先前调度的任务之后执行,而是意味着代码将阻塞,直到调度函数“返回”,它实际上是决定执行顺序的队列类型。
    • @BogdanAlexandru 这是正确的。如果您想要串行执行,即“任务将在先前调度的任务完成后执行”,那么您需要一个串行队列。要理解的是串行/并发调度和同步/异步调度在很大程度上是正交的。 (您可以将同步或异步调度到串行和并发队列。)另一种思考方式是:同步/异步主要与调度er(将块入队的事物)相关,而串行/concurrent 主要与 dispatched 块相关。
    【解决方案3】:

    作者是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

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

    【讨论】:

      【解决方案4】:

      当你把一个块对象放到一个并发队列上时,你自己的程序 总是立即继续而不等待队列执行 编码。这是因为并发队列,顾名思义, 在主线程以外的线程上运行他们的代码。

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

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

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

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

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

      【讨论】:

        猜你喜欢
        • 2018-07-29
        • 1970-01-01
        • 2013-12-28
        • 2019-05-27
        • 2012-02-22
        • 2022-12-10
        • 2016-03-31
        • 1970-01-01
        • 2014-04-02
        相关资源
        最近更新 更多