DispatchQueue 异步问题

DispatchQueue async issue

var numbers: [Int] = []
var queue = DispatchQueue(label: "myqueue", attributes: .concurrent)

DispatchQueue.concurrentPerform(iterations: 10) { i in
    
    queue.async() {
        print(i)
        let last = numbers.last ?? 0
        numbers.append(last + 1)
    }
}

sleep(1)
print(numbers)

输出:

[1, 2, 3, 4, 5] --(可能不同)

异步块中的工作项运行了 10 次,但为什么数组中的数字少于 10 个?

第二个问题,如果我把async改成sync,数字还是小于10,为什么不是[1 2 3 4 5 6 7 8 9 10]?

Swift 中的数组不是线程安全的。当您同时访问它们时会发生什么是不确定的。所以一些元素没有被添加,或者添加了错误的元素,或者你的程序崩溃,都是 运行 宁代码的可能结果。

更改为 sync 没有帮助,因为您仍在 post 处理 并发 队列,这将 运行他们并发,当你 post 使用 concurrentPerform.

同时处理它时

sync保证的是它returns工作完成后,使得它后面的代码运行s工作完成后。例如,如果在 sync 之后有一个额外的 print:

queue.sync {
    print(i)
    let last = numbers.last ?? 0
    numbers.append(last + 1)
}
print("Foo")

Foo保证在numbers.append(last + 1)之后打印。

另见 this guide

所以要实现[1,2,3,4,5,6,7,8,9,10],你应该post在一个串行队列上工作,这保证了工作将按顺序执行。或者,如果您只有一个并发队列,请使用 .barrier 标志:

queue.async(flags: .barrier) {

此外,如果您的实际意思是 concurrentPerform 使用 queue 进行“并发执行”,那么正如 所说,您应该这样做:

queue.async {
    DispatchQueue.concurrentPerform(iterations: 10) { i in
        print(i)
        someSerialQueue.async {
            let last = numbers.last ?? 0
            numbers.append(last + 1)
        }
    }
}