Swift object pool design sample


A generic object pool in Swift

The object pool sample is a creational design sample. The primary concept behind it’s that first you create a set of objects (a pool), then you definitely purchase & launch objects from the pool, as an alternative of continually creating and releasing them. 👍

Why? Efficiency enhancements. For instance the Dispatch framework makes use of an object pool sample to offer pre-created queues for the builders, as a result of making a queue (with an related thread) is an comparatively costly operation.

One other use case of the object pool sample is employees. For instance you need to obtain lots of of pictures from the online, however you’d prefer to obtain solely 5 concurrently you are able to do it with a pool of 5 employee objects. Most likely it’ll be loads cheaper to allocate a small variety of employees (that’ll really do the obtain activity), than create a brand new one for each single picture obtain request. 🖼

What in regards to the downsides of this sample? There are some. For instance in case you have employees in your pool, they could comprise states or delicate consumer knowledge. It’s a must to be very cautious with them aka. reset all the pieces. Additionally if you’re operating in a multi-threaded atmosphere you need to make your pool thread-safe.

Right here is an easy generic thread-safe object pool class:

import Basis

class Pool<T> {

    personal let lockQueue = DispatchQueue(label: "pool.lock.queue")
    personal let semaphore: DispatchSemaphore
    personal var objects = [T]()

    init(_ objects: [T]) {
        self.semaphore = DispatchSemaphore(worth: objects.rely)
        self.objects.reserveCapacity(objects.rely)
        self.objects.append(contentsOf: objects)
    }

    func purchase() -> T? {
        if self.semaphore.wait(timeout: .distantFuture) == .success, !self.objects.isEmpty {
            return self.lockQueue.sync {
                return self.objects.take away(at: 0)
            }
        }
        return nil
    }

    func launch(_ merchandise: T) {
        self.lockQueue.sync {
            self.objects.append(merchandise)
            self.semaphore.sign()
        }
    }
}


let pool = Pool<String>(["a", "b", "c"])

let a = pool.purchase()
print("(a ?? "n/a") acquired")
let b = pool.purchase()
print("(b ?? "n/a") acquired")
let c = pool.purchase()
print("(c ?? "n/a") acquired")

DispatchQueue.world(qos: .default).asyncAfter(deadline: .now() + .seconds(2)) {
    if let merchandise = b {
        pool.launch(merchandise)
    }
}

print("No extra useful resource within the pool, blocking thread till...")
let x = pool.purchase()
print("(x ?? "n/a") acquired once more")

As you may see the implementation is only a few traces. You may have the thread protected array of the generic pool objects, a dispatch semaphore that’ll block if there aren’t any objects accessible within the pool, and two strategies with a purpose to really use the thing pool.

Within the pattern you may see that if there aren’t any extra objects left within the pool, the present queue will likely be blocked till a useful resource is being freed & prepared to make use of. So be careful & do not block the principle thread by chance! 😉

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles