您问的问题是正确的,但我认为您有点困惑(主要是因为关于这个主题的帖子在互联网上不是很清晰)。
并发/串行
让我们看看如何创建新的调度队列:
let serialQueue = DispatchQueue(label: label)
如果您不指定其他附加参数,此队列将表现为串行队列:
这意味着在此队列上分派的每个块(同步或异步无关紧要)都将单独执行,没有其他块可以同时在该队列上执行。
这并不意味着其他任何事情都停止了,只是意味着如果在同一队列上调度了其他内容,则它将等待第一个块完成后再开始执行。其他线程和队列仍会按照自己的方式运行。
但是,您可以创建一个并发队列,不会限制此代码块的方式,而是,如果在同一时间在该队列上分派了更多的代码块,它将同时执行它们(在不同的线程上)。
let concurrentQueue = DispatchQueue(label: label,
qos: .background,
attributes: .concurrent,
autoreleaseFrequency: .inherit,
target: .global())
因此,您只需要将属性concurrent
传递给队列,它就不再是串行的了。
(我不会讨论其他参数,因为它们不是这个特定问题的重点,而且,我认为您可以在评论中链接的其他SO帖子中阅读有关它们的内容,或者如果这还不够,请提出另一个问题)
如果您想了解更多关于并发队列的信息(如果您不关心并发队列,请跳过此部分)
您可能会问:我什么时候需要使用并发队列呢?
好吧,比方说,让我们考虑一种使用情况,您想要同步共享资源的读操作:由于读操作可以同时进行而不会出现问题,您可以使用并发队列来实现。
但是,如果您想要在该共享资源上进行写入操作呢?
在这种情况下,写入需要充当“屏障”,在执行该写入期间,没有其他写入和读取可以同时对该资源进行操作。
为了获得这种行为,Swift代码可能如下所示:
concurrentQueue.async(flags: .barrier, execute: { /*your barriered block*/ })
换句话说,如果需要,您可以暂时将并发队列作为串行队列使用。
再次强调,所谓的并发/串行区别仅适用于分派到同一队列的块,与在其他线程/队列上执行的其他并发或串行工作无关。
同步/异步
这是完全不同的问题,与前面讨论的没有任何联系。
这两种方法用于调度某些代码块,相对于您在调用调度时所在的当前线程/队列。此调度调用会阻塞(同步)或不会阻塞(异步)该线程/队列的执行,同时在其他队列上执行您调度的代码。
比方说,我正在执行一个方法,在该方法中,我异步地将某些内容调度到其他队列上(我正在使用主队列,但它可以是任何队列):
func someMethod() {
var aString = "1"
DispatchQueue.main.async {
aString = "2"
}
print(aString)
}
这段代码会被派发到另一个队列上,可以在该队列上串行或并发执行,但这与当前队列上正在发生的事情无关(当前队列是调用someMethod的队列)。
当前队列上的代码将继续执行,并且不会等待该代码块完成后再打印该变量。这意味着很可能会看到它打印1而不是2。(更准确地说,你不知道哪个先执行)
如果改为同步调度,则始终会打印 2,因为当前队列会等待该代码块完成后才继续执行。
所以这将打印2:
func someMethod() {
var aString = "1"
DispatchQueue.main.sync {
aString = "2"
}
print(aString)
}
那么,这是否意味着在调用someMethod的队列实际上已经停止了?
嗯,这取决于当前的队列:
- 如果是串行的,则是的。已经调度到该队列或将在该队列上调度的所有块都必须等待该块完成。
- 如果是并发的,则不会。所有并发块将继续执行,只有特定的执行块将被阻塞,等待此调度调用完成其工作。当然,如果我们处于屏障情况下,则与串行队列一样。
当currentQueue和我们调度的队列相同时会发生什么?
假设我们正在使用串行队列(我认为这将是大多数用例)
- 如果我们调度同步,则会死锁。没有任何东西会在那个队列上执行。这是最糟糕的情况。
- 如果我们调度异步,则代码将在已经调度到该队列的所有代码之后执行(包括但不限于正在someMethod中执行的代码)
因此,在使用同步方法时要特别小心,确保您不在调度到同一队列中。
希望这可以让您更好地理解。
DQ.main.async
,那么任务将在其他后台队列上异步执行,在完成时会将控制权返回到主线程”。你为什么认为在主队列上调用async会使该代码片段在除主队列之外的其他队列中执行?无论您在哪个队列上调用async/sync,都会执行代码。唯一的区别就是您当前的队列是否等待结果。 - Roope