Swift - 如何在并发 enumerateObjects 块内填充字典?

问题描述 投票:0回答:2

是否可以在 enumerateObjects(options: .concurrent) 中填充字典或数组?尝试填充字典时,我继续收到 EXC_BAD_ACCESS 错误。当我添加信号量时它会起作用,但是在字典前面添加信号量也会增加大量开销,并且违背了我想要使用 enumerateObjects(options: .concurrent) 来提高性能的整个目的。 这是我目前拥有的代码:

func parseImgColor(_ cgImage: CGImage){
    
    let yRange = (0..<cgImage.height)
    let yArray: NSArray = yRange.map { $0 } as NSArray

    let xRange = (0..<cgImage.width)
    let xArray: NSArray = xRange.map { $0 } as NSArray
    
    var coordinateMap: [Coordinate : CoordColor] = [:]
    
    yArray.enumerateObjects(options: .concurrent) { yPosition, index, yStopPointer in
        guard let y: Int = yPosition as? Int else {
            yStopPointer.pointee = true
            return
        }
        xArray.enumerateObjects(options: .concurrent) { xPosition, index, xStopPointer in
            guard let x: Int = xPosition as? Int else {
                xStopPointer.pointee = true
                return
            }
            let coords = Coordinate(x: x, y: y)
            if x % 2 == 0{
                coordinateMap[coords] = CoordColor(value: UIColor.blue);
            } else {
                coordinateMap[coords] = CoordColor(value: UIColor.white);
            }
        }
    }
}

我用来定义字典的结构包括:

struct Coordinate: Hashable {
    let x: Int
    let y: Int
}

struct CoordColor: Hashable{
    let value: UIColor
}

失败示例图片: enter image description here

swift concurrency
2个回答
0
投票

如果繁重的计算发生在循环内部,那么也许在串行队列上收集结果不会那么糟糕。

另外,为什么不将两个 (x,y) 范围压缩在一起,然后使用类似

DispatchQueue.concurrentPerform()
的东西来并行化计算,而不是使用每个在并发队列上生成的两个嵌套循环?

所以这就是我会尝试做的:

// Image size
let width = 3
let height = 4

// Total number of iterations
let iterationCount = width * height

// Your dictionary key
struct Coordinate: Hashable, CustomDebugStringConvertible {
    var x: Int
    var y: Int

    var debugDescription: String {
        return "\(x).\(y)"
    }
}

// Spawn on concurrent queue
DispatchQueue.global().async {
    var result: [Coordinate: String] = [:]
    let resultQueue = DispatchQueue(label: "ResultCollectorQueue")

    DispatchQueue.concurrentPerform(iterations: iterationCount) { i in
        // Compute x,y for the image, however you could also zip xArray and yArray ranges together instead
        let x = i / width
        let y = i % width

        // Do something heavy

        // Collect the result on a serial queue
        resultQueue.async {
            result[Coordinate(x: x, y: y)] = "\(x) \(y)"
        }
    }

    // Pick up the result
    resultQueue.async {
        print("Got result: \(result)")
    }
}

objc.io 上有一份很棒的材料,深入探讨了并发映射的实现:https://talk.objc.io/episodes/S01E90-concurrent-map


0
投票

修改时可以锁定/解锁。

private static let locker = NSLock()

locker.lock()
...
...modify
...
locker.unlock()
© www.soinside.com 2019 - 2024. All rights reserved.