Ios 同步/异步的行为是否与串行/并发的行为类似,即它们都控制调度队列还是只控制同步/异步线程

Ios 同步/异步的行为是否与串行/并发的行为类似,即它们都控制调度队列还是只控制同步/异步线程,ios,swift,grand-central-dispatch,dispatch-queue,ios-multithreading,Ios,Swift,Grand Central Dispatch,Dispatch Queue,Ios Multithreading,关于stackoverflow的大多数答案都暗示,同步与异步行为与串行与并发队列概念的差异非常相似。就像@Roope第一条评论中的链接一样 我开始这么想 串行和并发与DispatchQueue有关,而sync/async则与线程上执行操作的方式有关。 我说得对吗 比如,如果我们有DQ.main.sync,那么任务/操作闭包将以同步方式在这个串行(主)队列上执行。 而且,若我执行了DQ.main.async,那个么任务将在其他后台队列上异步执行,并且在完成时将返回对主线程的控制。 而且,因为mai

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

我开始这么想 串行和并发与
DispatchQueue
有关,而sync/async则与线程上执行操作的方式有关。 我说得对吗

比如,如果我们有
DQ.main.sync
,那么任务/操作闭包将以同步方式在这个串行(主)队列上执行。 而且,若我执行了
DQ.main.async
,那个么任务将在其他后台队列上异步执行,并且在完成时将返回对主线程的控制。 而且,因为main是一个串行队列,所以在当前闭包任务完成执行之前,它不会让任何其他任务/操作进入执行状态/开始执行

那么,
DQ.global().sync
将在其任务/操作已分配的线程上同步执行任务,即通过阻止该特定线程上的任何上下文切换,阻止该线程执行任何其他任务/操作。 而且,由于global是一个并发队列,它将继续将其中存在的任务置于执行状态,而不管以前的任务/操作的执行状态如何

DQ.global().async
将允许在已放置操作闭包以供执行的线程上进行上下文切换


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

你问的问题是对的,但我认为你有点困惑(主要是因为互联网上关于这个主题的帖子不太清楚)

并发/串行 让我们看看如何创建新的调度队列:

let serialQueue = DispatchQueue(label: label)
如果未指定任何其他附加参数,此队列将作为串行队列: 这意味着在该队列上调度的每个块(同步或异步并不重要)将单独执行,而不可能在同一队列上同时执行其他块

这并不意味着停止其他任何操作,只是意味着如果在同一队列上调度其他操作,它将等待第一个块完成,然后再开始执行。其他线程和队列仍将自己运行


但是,您可以创建一个并发队列,该队列不会以这种方式约束这些代码块,相反,如果同时在同一队列上调度更多的代码块,它将同时(在不同的线程上)执行这些代码块

因此,您只需要将属性
concurrent
传递给队列,它就不再是串行的了

(我不会谈论其他参数,因为它们不是这个特定问题的焦点,我认为,你可以在评论中链接的其他SO帖子中阅读它们,或者,如果这还不够,你可以问另一个问题)


如果您想进一步了解并发队列(又称:如果您不关心并发队列,请跳过) 你可以问:我什么时候需要并发队列

好的,举个例子,让我们考虑一个用例,您希望在共享资源上同步读取:因为读取可以同时完成而不会出现问题,所以您可以使用并发队列来实现这一点

但是如果你想在共享资源上写东西呢? 在这种情况下,写操作需要充当“屏障”,在写操作的执行过程中,其他任何写操作和读操作都不能同时对该资源进行操作。 要获得这种行为,swift代码将如下所示

concurrentQueue.async(flags: .barrier, execute: { /*your barriered block*/ })
因此,换句话说,如果需要,您可以使并发队列临时作为串行队列工作


同样,并发/串行区分仅对调度到同一队列的块有效,它与可以在另一个线程/队列上完成的其他并发或串行工作无关

同步/异步 这完全是另一个问题,与前一个问题几乎没有联系

这两种分派代码块的方法与分派调用时的当前线程/队列相关。当执行您在另一个队列上分派的代码时,此分派调用会阻止(在同步的情况下)或不阻止(异步)该线程/队列的执行

假设我正在执行一个方法,在该方法中,我在另一个队列(我使用的是主队列,但它可以是任何队列)上调度异步内容:

发生的情况是,此代码块被调度到另一个队列上,并且可以在该队列上串行或并发执行,但与当前队列(调用someMethod的队列)上发生的事情没有关联

在当前队列上发生的情况是,代码将继续执行,并且不会在打印该变量之前等待该块完成。 这意味着,您很可能会看到它打印1而不是2。(更确切地说,你不知道首先会发生什么)

相反,如果您将其分派为sync,那么您将始终打印2而不是1,因为当前队列将在继续执行之前等待该代码块完成

因此,这将打印2:

func someMethod() {
    var aString = "1"
    DispatchQueue.main.sync {
        aString = "2"
    }
    print(aString)
}
但这是否意味着调用someMethod的队列实际上已停止? 嗯,这取决于当前队列:

  • 如果是连载的,那就说是。以前分配给该队列或将在该队列上分配的所有块都必须等待该块完成
  • 如果是并发的,则不是。所有并发块将继续执行,只有这个特定的执行块将被阻止,等待这个调度调用完成它的工作。当然如果
    func someMethod() {
        var aString = "1"
        DispatchQueue.main.async {
            aString = "2"
        }
        print(aString)
    }
    
    func someMethod() {
        var aString = "1"
        DispatchQueue.main.sync {
            aString = "2"
        }
        print(aString)
    }
    
    let task = URLSession.shared.dataTask(with: url) { data, _, error in
        // parse the response
        DispatchQueue.main.async { 
            // update the UI
        }
        // do something else
    }
    task.resume()