title
import Foundation
private let parallelQueue = DispatchQueue(label: "Sequence#parallelMapQueue", attributes: .concurrent)
extension Sequence {
// parallelMap
//Apply transform in parallel to all elements and return an array of return values that maintain their order
//
func parallelMap<T>(_ transform: @escaping (Element) throws -> T) rethrows -> [T] {
let group = DispatchGroup()
let semaphore = DispatchSemaphore(value: 1)
var result: [(Int, Result<T, Error>)] = []
zip(0..., self)
.forEach { i, v in
parallelQueue.async(group: group) {
let r = Result { try transform(v) }
semaphore.wait()
defer { semaphore.signal() }
result.append((i, r))
}
}
group.wait()
return try result
.sorted { $0.0 < $1.0 }
.map { try $0.1.get() }
}
}
print(
(0...10)
.parallelMap { i -> Int in
let t = UInt32([0, 2, 3, 5].randomElement()!)
sleep(t)
print(i, t)
return i + 1
}
)
//Output example
//
// 0 0
// 4 0
// 10 0
// 1 2
// 2 2
// 3 2
// 5 2
// 7 2
// 6 3
// 9 3
// 8 5
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
It can be seen that they are executed separately (parallel) and that the order of the return values is maintained.
Recommended Posts