这些队列管理提供给GCD的任务,并按FIFO顺序执行这些任务。这保证了添加到队列中的第一个任务是队列中启动的第一个任务,添加的第二个任务将是第二个启动的,依此类推。以下代码
let anotherQueue = DispatchQueue(label: "com.gcdTest.Queue", qos: .userInteractive)
anotherQueue.async {
anotherQueue.async{
anotherQueue.async{
anotherQueue.async {
print("task 6")
for _ in 1...300 { }
}
}
print("task 3")
for _ in 301...600 {}
}
anotherQueue.async{
anotherQueue.async{
print("task 5")
for _ in 700...900 {}
}
print("task 4")
for _ in 5000...7000 {}
}
print("task 1")
for _ in 9000...10000 {}
}
anotherQueue.async {
print("task 2")
for _ in 1...1000 {}
}
产生输出
task 1
task 2
task 3
task 4
task 5
task 6
但是,当我们同时运行相同的代码时,它会产生不可预测的输出。例:-将第一行代码更改为下面一行
let anotherQueue = DispatchQueue(label: "com.gcdTest.Queue", qos: .userInteractive, attributes: .concurrent)
输出
task 3
task 2
task 1
task 4
task 5
task 6
根据定义,它声明并发队列中的任务按添加…的顺序开始。这就是你所得到的保证!
因此,期望由串行队列(默认情况下)产生类似的输出。(task1,task2,task3,task4,task5,task6)请任何人帮助我,我走错了。
发布于 2018-03-15 17:03:29
总之,GCD总是按照任务被分派到队列的顺序启动队列上的任务。在串行队列的情况下,这意味着它们将按该顺序依次运行,而且这种行为很容易被观察到。
但是,在并发队列的情况下,虽然它将以排队顺序启动任务,但对于连续快速分派的任务,它们也可以依次快速启动,并同时运行。简而言之,它们可能在几乎同时开始运行,因此您无法保证将首先遇到其各自的print
语句。仅仅因为并发队列连续几毫秒地启动一个任务,就不能保证这两个任务遇到各自的print
语句的顺序。
简而言之,与print
语句序列的确定性行为不同,您有一个简单的非确定性行为竞赛。
顺便提一下,虽然很明显,您的示例在并发队列中使用时引入了竞争,但是应该注意,由于嵌套的调度语句,您的串行队列中也会有竞争条件。在串行队列上,行为序列看起来是完全可预测的,但事实并非如此。
让我们考虑一下示例的简化版本。我假设我们将从主线程开始:
queue.async {
queue.async {
print("task 3")
}
print("task 1")
}
queue.async {
print("task 2")
}
显然,任务1将首先添加到队列中,如果该队列是空闲的,它将立即在该后台线程上启动,而主线程则继续进行。但是,当主线程上的代码接近任务2的分派时,任务1将开始并继续执行任务3,在任务2和任务3的分派之间有一个典型的竞争。
现在,在实践中,您将看到任务2在任务3之前被分派,但是引入非确定性行为并不需要太大的延迟。例如,在我的计算机上,如果在调度任务2之前,Thread.sleep(forTimeInterval: 0.00005)
显示了不确定的行为。但是即使没有延迟(或一定数量的迭代的for
循环),这种行为在技术上也是不确定的。
但是,我们可以创建简单的示例,以消除上述示例中隐含的竞争,但仍然说明了您最初询问的串行队列行为和并发队列行为之间的区别:
for i in 0 ..< 10 {
queue.async { [i] in
print(i)
}
}
这保证在串行队列上按顺序打印,但不一定在并发队列上打印。
https://stackoverflow.com/questions/49145005
复制相似问题