我使用Thread Sanitizer在Swift应用程序中发现了一个数据竞争,因此我第一次尝试修复竞争条件,将违规的class
转换为actor
。竞争导致的崩溃似乎已经消失,但Thread Sanitizer仍然说代码中存在数据竞争,我认为这在actor
中应该是不可能的。
我不能在这里发布整个actor
,但这里是发生竞争的代码:
actor SampleActor {
private var things = Set<Int>()
func addThing(_ newThing: Int, seconds: Double) {
things.insert(newThing)
Task {
try await Task.sleep(nanoseconds: UInt64(seconds * 1_000_000_000))
self.things.remove(newThing)
}
}
}
// Code to cause the race
let sample = SampleActor()
for n in 0 ..< 1000 {
Task {
await sample.addThing(n, seconds: Double.random(in: 0...1.0))
}
}
我可能用了错误的方法,但是我需要向SampleActor
的对象集中添加一个对象,并在一段时间后自动删除它。
有没有更好的方法来做到这一点?在使用actor
来避免这种情况下的数据竞争方面,我遗漏了什么?SampleActor.things
不应该对这里的竞争免疫吗,因为它是actor
的属性?
2条答案
按热度按时间goqiplq21#
卸下
actor
中的Task {
部件将
async
添加到函数tgabmvqs2#
这里没有数据竞争。这是TSAN中的一个bug。据报道,他们一直在改进它与参与者的交互,但至少在Swift 5.7.2中,仍然存在问题。例如,请参见https://github.com/apple/swift/issues/57902或https://github.com/apple/swift/issues/57749。
正如lorem ipsum所说(+1),在
addThing
中放弃使用Task {…}
是明智的,这样可以获得更简洁的代码,享受结构化并发的好处,但这不是这里的问题,暂时避免使用具有Swift并发的TSAN。