快速并行执行任务并显示进度

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

我有以下代码

func randomIndices(n: Int) -> [Int] {
    var result: [Int] = []
    var used: [Bool] = (0 ..< n).map { _ in false }
    for _ in 0 ..< n {
        var r = Int.random(in: 0 ..< n)
        while used[r] {
            r = (r + 1) % n
        }
        used[r] = true
        result.append(r)
    }
    return result
}

func split<R>(array: [R], n: Int) -> [[R]] {
    var result: [[R]] = (0 ..< n).map { _ in [] }
    var index = 0
    for item in array {
        result[index].append(item)
        index = (index + 1) % n
    }
    return result
}

func inParallell<R>(count: Int, n: Int = 4, function: (Int) -> R, progress: ((Double) -> Void)? = nil) -> [R] {
    
    let indices = split(array: randomIndices(n: count), n: n)
    var res: [R?] = .init(repeating: nil, count: count)
    
    let lock = NSRecursiveLock()
    var meter = 0.0, step = 1.0 / Double(count)
    DispatchQueue.concurrentPerform(iterations: indices.count) { i in
        for index in indices[i] {
            let result = function(index)
            lock.lock()
            res[index] = result
            meter += 1.0 / step
            DispatchQueue.main.async {
                print("inParallell meter \(meter)")
                progress?(meter)
            }
            lock.unlock()
        }
    }
    DispatchQueue.main.async {
        progress?(1)
    }
    return res.map({ $0! })
}

func waitSomeTime() {
    var x = 0
    for i in 0 ..< 1_000_000 {
        x += i
    }
}
struct InParallellTestView: View {
    @State var progress = 0.0
    var body: some View {
        ProgressView(value: progress)
            .onAppear {
                let _ = inParallell(count: 10, function: { _ in
                    waitSomeTime()
                }, progress: { p in progress = p })
            }
    }
}

这个想法是进度条应该在代码运行时更新,但是如果我查看打印输出,它会重复显示“inParallellmeter 100.0”,即所有仪表更新都发生在最后。我已经在“DispatchQueue.global(qos: .utility).sync”块中尝试了整个 ConcurrentPerform 块,但这并没有改变结果。

我尝试运行代码并将 DispatchQueue.main.async 更改为同步,但这也没有什么区别。结果是进度条的所有更新都发生在计算完成后。

swiftui dispatch-queue
1个回答
0
投票

问题是

concurrentPerform
阻塞了调用者的线程。通常我们会将其分派到全局队列,以避免阻塞主线程。

© www.soinside.com 2019 - 2024. All rights reserved.