Swift 多线程环境中的 Copy-on-Write

Posted

技术标签:

【中文标题】Swift 多线程环境中的 Copy-on-Write【英文标题】:Copy-on-Write in Multi-threaded environment in Swift 【发布时间】:2018-06-19 06:18:52 【问题描述】:

我在Arrays 中阅读了关于Copy-on-Write 优化概念以及Swift 中的其他数据结构。

我想知道的是Copy-on-Write如何在多线程环境中工作。

    let arr1 = [1, 2, 3, 4]
    let arr2 = arr1
    arr1.withUnsafeBytes  print("arr1:", $0.baseAddress)  //0x000060000007ee60
    arr2.withUnsafeBytes  print("arr2:", $0.baseAddress)  //0x000060000007ee60

    DispatchQueue.global(qos: .default).async 
        let arr3 = arr1
        arr3.withUnsafeBytes  print("arr3:", $0.baseAddress)  //0x000060000007ee60
    

在上面的代码中,arr1arr2 最初具有与 copy-on-write 中预期的相同的地址。但是,arr3 也与 arr1arr2 共享相同的内存,尽管它在不同的线程上执行。

据我所知,每个线程都有不同的堆栈分配。那为什么arr3 还在同一个位置呢?

谁能解释一下它是如何工作的。

【问题讨论】:

let arr3 = arr1 使两个数组(最初)共享元素存储——为什么在哪个线程上执行代码很重要?顺便说一句,元素存储是分配内存的,即在堆上,而不是在堆栈上。 @MartinR 元素存储不取决于它是什么类型的元素吗? 我不确定您的意思以及这与问题有何关系。数组是一个(固定大小的)struct,带有一个指向(分配的)元素存储的指针。 – 看看mikeash.com/pyblog/…,其中包含 COW 的 Array 类型被“重新发明”,这可能会提供一些见解。 【参考方案1】:

您没有查看数组的地址。您正在查看数组的内部后备存储地址,该地址是共享的和堆分配的。

如果您想查看堆栈分配的数组容器的地址(指向后备存储的部分),那么您的意思是:

var arr1 = [1, 2, 3, 4]
var arr2 = arr1
withUnsafePointer(to: &arr1)  print("arr1:", $0) 
withUnsafePointer(to: &arr2)  print("arr2:", $0) 

DispatchQueue.global(qos: .default).async 
    let arr3 = arr1
    withUnsafePointer(to: arr3)  print("arr3:", $0) 


// =>
arr1: 0x0000000122d671e0   // local stack
arr2: 0x0000000122d671e8   // local stack (next address)
arr3: 0x0000700000e48d10   // heap

我相信这是您所期待的结果。

【讨论】:

正是..:) 非常感谢。

以上是关于Swift 多线程环境中的 Copy-on-Write的主要内容,如果未能解决你的问题,请参考以下文章

多线程 - Swift 中的 DispatchQueue asyncAfter 延迟

GCD多线程在swift中的变化

多线程环境中的 JDBC 事务

多线程环境中的 PetaPoco 事务

C++ 多线程环境中的内存访问

多线程环境中的 Shiro