Created
November 10, 2020 13:58
-
-
Save dydus0x14/516f84695ad39496123731d9a9a4fe4a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
protocol Atomic { | |
var value: Int { get } | |
func increment() | |
} | |
class SwiftAtomic: Atomic { | |
private let counter = ManagedAtomic<Int>(0) | |
var value: Int { | |
counter.load(ordering: .relaxed) | |
} | |
func increment() { | |
counter.wrappingIncrement(ordering: .relaxed) | |
} | |
} | |
class QueueAtomic: Atomic { | |
private var counter = 0 | |
private let queue = DispatchQueue(label: "") | |
var value: Int { | |
queue.sync { | |
self.counter | |
} | |
} | |
func increment() { | |
queue.sync { | |
self.counter += 1 | |
} | |
} | |
} | |
class NSLockAtomic: Atomic { | |
private var counter = 0 | |
private let lock = NSLock() | |
var value: Int { | |
var result = 0 | |
lock.lock() | |
result = counter | |
lock.unlock() | |
return result | |
} | |
func increment() { | |
lock.lock() | |
counter += 1 | |
lock.unlock() | |
} | |
} | |
class SpinLock: Atomic { | |
var lock = os_unfair_lock() | |
var counter = 0 | |
var value: Int { | |
var result = 0 | |
os_unfair_lock_lock(&lock) | |
result = counter | |
os_unfair_lock_unlock(&lock) | |
return result | |
} | |
func increment() { | |
os_unfair_lock_lock(&lock) | |
counter += 1 | |
os_unfair_lock_unlock(&lock) | |
} | |
} | |
class AtomicTest { | |
func run() { | |
for index in 1...10 { | |
let swiftAtomic = SwiftAtomic() | |
let queueAtomic = QueueAtomic() | |
let nslockAtomic = NSLockAtomic() | |
let spinlockAtomic = SpinLock() | |
let time1 = measure { | |
self.run(iterations: index, counter: swiftAtomic) | |
} | |
let time2 = measure { | |
self.run(iterations: index, counter: queueAtomic) | |
} | |
let time3 = measure { | |
self.run(iterations: index, counter: nslockAtomic) | |
} | |
let time4 = measure { | |
self.run(iterations: index, counter: spinlockAtomic) | |
} | |
print(String(format: "%.3f;%.3f;%.3f;%.3f", time1, time2, time3, time4)) | |
} | |
} | |
func run(iterations: Int, counter: Atomic) { | |
DispatchQueue.concurrentPerform(iterations: iterations) { _ in | |
for index in 0 ..< 1_000_000 { | |
if index % 100 == 0 { | |
_ = counter.value | |
} else { | |
counter.increment() | |
} | |
} | |
} | |
} | |
func measure(block: () -> Void) -> TimeInterval { | |
let startTime = CFAbsoluteTimeGetCurrent() | |
block() | |
let endTime = CFAbsoluteTimeGetCurrent() | |
let totalTime = endTime - startTime | |
return totalTime | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment