我有以下代码
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 更改为同步,但这也没有什么区别。结果是进度条的所有更新都发生在计算完成后。
问题是
concurrentPerform
阻塞了调用者的线程。通常我们会将其分派到全局队列,以避免阻塞主线程。