我的代码是:
import Foundation
let q1 = DispatchQueue(
label: "test-1",
qos: .userInteractive,
attributes: .concurrent
)
let q2 = DispatchQueue(label: "test-2")
var i = 0;
q1.async {
for _ in 0..<10 {
i+=1
print("async 1-1: ", i)
}
}
q1.async {
for _ in 0..<10 {
i+=1
print("async 1-2: ", i)
}
}
q2.async {
for _ in 0..<10 {
i+=1
print("async 2: ", i)
}
}
for _ in 0..<10 {
i+=1
print("sync: ", i)
}
在操场上运行它,似乎写入操作是跨不同的 DispatchQueue 串行的:
测试几个场景,似乎写入操作是跨不同 DispatchQueue 的串行操作。如果是并发的,至少应该有一些重复值吧?
我需要为 var i 添加锁吗?我是 swift 新手,不确定我对 DispatchQueue 的理解是否正确。
这段代码不是线程安全的。行为将是不可预测的。您可能只会得到无效的结果。你可能会崩溃。它通常看起来可以正常工作(即使它不安全)
使用 GCD 时,我建议暂时打开“线程清理器”(TSAN),它将在识别这些数据争用方面做出可靠的工作。请参阅“尽早诊断内存、线程和崩溃问题”的检测应用程序线程之间的数据争用部分。只需单击“Thread sanitizer”复选框并运行应用程序,您就会在控制台中看到报告的问题。
回答你的问题,在 GCD 时代,是的,我们会添加我们自己的同步。例如,锁定或确保为与此共享可变状态的所有交互创建一个单独的串行队列。
现在我们根本不确定 GCD,而是使用 Swift 并发。在 Swift 并发中,我们通过使用“参与者”来消除数据竞争。请参阅 WWDC 视频使用 Swift Actor 保护可变状态和使用 Swift Concurrency 消除数据争用。如果您不熟悉 Swift 并发,请参阅 Meet async/await in Swift,以及该页面上链接的其他视频。