Crt Tax
Crt Tax

Reputation: 397

Does Map method of Swift Array implemented concurrently?

Checked the doc, but not talks about many details of implementation. Wondering if for a large array, does it perform in concurrent way?

Upvotes: 1

Views: 1430

Answers (1)

Alexander
Alexander

Reputation: 63167

The map implementation of Array specifically doesn't perform any multithreading, but there's nothing that says you couldn't make a concurrent implementation. Here's one that's generalized to work with any Sequence:

import Dispatch


class SharedSynchronizedArray<T> {
    var array = [T]()
    let operationQueue = DispatchQueue(label: "SharedSynchronizedArray")

    func append(_ newElement: T) {
        operationQueue.sync {
            array.append(newElement)
        }
    }
}

public struct ConcurrentSequence<Base, Element>: Sequence
    where Base: Sequence, Element == Base.Iterator.Element {
    let base: Base

    public func makeIterator() -> Base.Iterator {
        return base.makeIterator()
    }

    public func map<T>(_ transform: @escaping (Element) -> T) -> [T] {
        let group = DispatchGroup()

        let resultsStorageQueue = DispatchQueue(label: "resultStorageQueue")
        let results = SharedSynchronizedArray<T>()

        let processingQueue = DispatchQueue(
            label: "processingQueue",
            attributes: [.concurrent]
        )

        for element in self {
            group.enter()
            print("Entered DispatchGroup for \(element)")

            var result: T?
            let workItem = DispatchWorkItem{ result = transform(element) }

            processingQueue.async(execute: workItem)

            resultsStorageQueue.async {
                workItem.wait()
                guard let unwrappedResult = result else {
                    fatalError("The work item was completed, but the result wasn't set!")
                }
                results.append(unwrappedResult) 


                group.leave()
                print("Exited DispatchGroup for \(element)")
            }
        }
        print("Started Waiting on DispatchGroup")
        group.wait()
        print("DispatchGroup done")

        return results.array
    }


}

public extension Sequence {
    public var parallel: ConcurrentSequence<Self, Iterator.Element> { 
        return ConcurrentSequence(base: self)
    }
}

print("Start")

import Foundation

let input = Array(0..<100)
let output: [Int] = input.parallel.map {
    let randomDuration = TimeInterval(Float(arc4random()) / Float(UInt32.max))
    Thread.sleep(forTimeInterval: randomDuration)
    print("Transforming \($0)")
    return $0 * 2
}

print(output)
// print(output.parallel.filter{ $0 % 3 == 0 })

print("Done")

Upvotes: 6

Related Questions