闭包线程安全吗?
Are closures thread safe?
假设我有一个这样的class:
class Bla {
var callback: (() -> Void)?
// doStuff will be called from multiple threads
func doStuff() {
callback?()
}
}
从多个线程调用闭包是线程安全的吗?闭包在此期间不会被修改,只会被调用。
闭包内部是线程安全代码。
不幸的是,线程安全不是一个直截了当的问题。具体来说,虽然块的读取对于多个线程是安全的。
在 swift 中,闭包通过引用传递。当您将它分配给“var callback”时,它会在堆中接收一个内存地址。只要变量在其他线程读取访问时没有更改,该地址就可以由多个线程同时读取。即使您在块中捕获了一个变量,该变量也会被块捕获,如果它不是引用类型,甚至可以通过闭包进行修改。不过,您肯定要小心在调用站点内所做的事情。例如,如果闭包被多个线程调用并且在你内部传递了 say..
var i = 0
callback = {
i += 1
}
for _ in 0...100 {
DispatchQueue.global().async {
bla.closure()
}
}
这显然不再被认为是“线程安全的”,因为您仍在通过多个线程进行变异。例如两个或三个线程可能读取 1 并加 1,另外十二个线程可能读取 5 并在 return 上写入 6;或更糟的是,第二个线程最后完成,在 100 次调用后你有 i = 2.
此外,如果“var i”是引用类型,程序可能会因错误访问异常而崩溃。
假设我有一个这样的class:
class Bla {
var callback: (() -> Void)?
// doStuff will be called from multiple threads
func doStuff() {
callback?()
}
}
从多个线程调用闭包是线程安全的吗?闭包在此期间不会被修改,只会被调用。
闭包内部是线程安全代码。
不幸的是,线程安全不是一个直截了当的问题。具体来说,虽然块的读取对于多个线程是安全的。
在 swift 中,闭包通过引用传递。当您将它分配给“var callback”时,它会在堆中接收一个内存地址。只要变量在其他线程读取访问时没有更改,该地址就可以由多个线程同时读取。即使您在块中捕获了一个变量,该变量也会被块捕获,如果它不是引用类型,甚至可以通过闭包进行修改。不过,您肯定要小心在调用站点内所做的事情。例如,如果闭包被多个线程调用并且在你内部传递了 say..
var i = 0
callback = {
i += 1
}
for _ in 0...100 {
DispatchQueue.global().async {
bla.closure()
}
}
这显然不再被认为是“线程安全的”,因为您仍在通过多个线程进行变异。例如两个或三个线程可能读取 1 并加 1,另外十二个线程可能读取 5 并在 return 上写入 6;或更糟的是,第二个线程最后完成,在 100 次调用后你有 i = 2.
此外,如果“var i”是引用类型,程序可能会因错误访问异常而崩溃。