ios - 同步/异步的行为是否类似于串行/并发,即它们都控制DispatchQueues还是仅执行同步/异步控制线程

标签 ios swift grand-central-dispatch dispatch-queue ios-multithreading

关于stackoverflow的大多数答案都暗示着同步与异步行为与串行与并发队列概念差异非常相似。就像@Roope在第一个评论中的链接一样

我开始认为
串行和并发与DispatchQueue和sync / async有关,用于了解如何在线程上执行操作。
我对吗?

就像我们有DQ.main.sync一样,任务/操作的关闭将以同步方式在此串行(主)队列上执行。
并且,如果我执行DQ.main.async,那么任务将在其他一些后台队列上异步获取,并且在完成时将返回对主线程的控制。
而且,由于main是一个串行队列,因此它不会让任何其他任务/操作进入执行状态/开始执行,直到当前的关闭任务完成了执行。

然后,DQ.global().sync将在已为其分配了任务/操作的线程上同步执行任务,即,它将通过阻止该特定线程上的任何上下文切换来阻止该线程执行任何其他任务/操作。
并且,由于global是并发队列,因此它将与当前任务/操作的执行状态无关地继续将其中存在的任务置于执行状态。
DQ.global().async将允许在已对其执行操作关闭的线程上进行上下文切换

这是对上面dispatchQueues和sync vs async的正确解释吗?

最佳答案

我开始认为Serial和并发与DispatchQueue有关,并且在操作如何在线程上执行同步/异步处理方面。

是的,串行或并发队列的选择决定了要调度到的队列的行为,但是sync / async与该代码在其他队列上的运行方式无关。相反,它决定了您从中调度线程的行为。因此,简而言之:

  • 目标队列是串行的还是并发的,决定了目标队列的行为(即,该队列能否与其他已调度到该队列的事物同时运行此闭包);
  • ,而syncasync则指示要从其分派的当前线程的行为(即,调用线程应等待直到分派的代码完成还是不结束)。

  • 因此,串行/并发会影响要调度到的目标队列,而sync / async会影响要调度的当前线程。

    您继续说:

    就像我们有DQ.main.sync一样,任务/操作的关闭将以同步方式在此串行(主)队列上执行。

    我可能会这样改写:“如果我们有DQ.main.sync,那么当前线程将等待主队列执行此关闭操作。”

    请记住,“同步方式”与目标队列(在DQ.main.sync示例中的主队列)中发生的事情无关,而是与您从中调用sync的线程无关。当前线程是否要等待?

    FWIW,我们不经常使用DQ.main.sync,因为十分之九,我们只是这样做以调度一些UI更新,因此通常无需等待。它很小,但是我们几乎总是使用DQ.main.async。当我们尝试与某些资源提供线程安全的交互时,我们确实使用sync。在这种情况下,sync可能非常有用。但这通常不需要与main结合使用,而只会带来效率低下的情况。

    并且,如果我执行DQ.main.async,那么任务将在其他一些后台队列上异步获取,并且在完成时将返回对主线程的控制。

    没有。

    当您执行DQ.main.async时,您指定闭包将在主队列(您调度到的队列)上异步运行,并且您的当前线程(大概是后台线程)不需要等待,而是立即等待继续。

    例如,考虑一个示例网络请求,该请求的响应在URLSession的后台串行队列上处理:
    let task = URLSession.shared.dataTask(with: url) { data, _, error in
        // parse the response
        DispatchQueue.main.async { 
            // update the UI
        }
        // do something else
    }
    task.resume()
    

    因此,解析是在URLSession后台线程上进行的,它向主线程调度UI更新,然后对该后台线程进行其他操作。 syncasync的全部目的是“做其他事情”是否必须等待“更新UI”完成。在这种情况下,主要是在处理UI更新时没有必要阻止当前的后台线程,因此我们使用async

    然后,DQ.global().sync将在已为其分配了任务/操作的线程上同步执行任务,即...

    是的DQ.global().sync说:“在后台队列上运行此关闭,但阻塞当前线程,直到完成关闭为止。”

    不用说,实际上,我们永远不会做DQ.global().sync。阻止当前线程等待在全局队列上运行的线程没有任何意义。将闭包分派到全局队列的重点是,您不必阻塞当前线程。如果您正在考虑使用DQ.global().sync,则最好还是在当前线程上运行它,因为无论如何都会阻止它。 (实际上,GCD知道DQ.global().sync并不能实现任何目的,并且作为一种优化,它通常还是会在当前线程上运行它。)

    现在,如果出于某种原因要使用async或使用一些自定义队列,则可能有意义。但是,通常没有必要进行DQ.global().sync

    ...它将通过阻止该特定线程上的任何上下文切换来阻止该线程执行任何其他任务/操作。

    没有。
    sync不会影响“该线程”(全局队列的工作线程)。 sync影响您从其分派此代码块的当前线程。当前线程将等待全局队列执行调度的代码(sync)还是不执行(async)?

    并且,由于global是并发队列,因此它将继续将其中存在的任务置于执行状态,而与先前任务/操作的执行状态无关。

    是。再说一遍,我可能会这样改写:“而且,由于global是当前队列,因此该闭包将被安排为立即运行,而不管该队列上可能已经在运行什么了。”

    技术上的区别是,当您将某些内容分派到并发队列时,通常它通常立即开始,有时却没有。也许您CPU上的所有内核都捆绑在一起运行其他功能。或者,也许您已经调度了许多块,并且暂时耗尽了GCD数量非常有限的“工作线程”。最重要的是,尽管通常会立即开始,但是总会有资源限制阻止它这样做。

    但这是一个细节:从概念上讲,当您调度到全局队列时,是的,它通常会立即开始运行,即使您可能已经调度到该队列的其他闭包尚未完成。

    DQ.global().async将允许在已对其执行操作关闭的线程上进行上下文切换。

    我可能会避免使用“上下文切换”一词,因为它具有非常具体的含义,可能超出了此问题的范围。如果您真的有兴趣,可以查看WWDC 2017视频Modernizing Grand Central Dispatch Usage

    我描述DQ.global().async的方式是,它只是“在全局队列执行分派的关闭时允许当前线程继续运行,不受阻塞。”这是一种极为常见的技术,通常从主队列调用该技术,以将一些计算密集型代码分派到某个全局队列,但不等待其完成,从而使主线程可以自由处理UI事件,从而产生响应速度更快的用户界面。

    关于ios - 同步/异步的行为是否类似于串行/并发,即它们都控制DispatchQueues还是仅执行同步/异步控制线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58904936/

    相关文章:

    ios - 如何将字符串解析为 NSTimeInterval

    swift - 使用 swift 和 alamofire 将视频(和属性)上传到 YouTube

    ios - 射弹并非来自正确的位置

    ios - 用相机胶卷图像填充桌面 View

    objective-c - 将延迟的 semaphore_signal 发送到 macOS Grand Central Dispatch 应用程序中的信号量是一个好习惯吗?

    cocoa-touch - 主要的 Grand Central Dispatch 队列是串行的还是并发的?

    ios - Swift Sprite Kit 传递 Bool

    ios - NSURLConnection(作为 AFNetworking 的一部分)不调用 NSURLConnectionDataDelegate 委托(delegate)

    ios - 如何实现代码以在 Swift for iOS 中在 MapKit 中进行可拖动的注释?

    swift - 附加到类内部的数组实际上并不是附加到调用对象?