Created
July 10, 2018 21:54
-
-
Save marciniwanicki/70e89b5dd93ff405e49d6ccd93b854e8 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
// | |
// Created by Marcin Iwanicki on 10/07/2018. | |
// Copyright © 2018 Marcin Iwanicki. All rights reserved. | |
// | |
import XCTest | |
// ----------------------------------------------------------------------------- | |
// Tests | |
// ----------------------------------------------------------------------------- | |
class SwiftSyncTestTests: XCTestCase { | |
private let iterations = 100000 | |
func testCreateNSLock() { | |
printTestName("Create - NSLock") | |
measure { | |
for _ in 0...iterations { | |
_ = NSLock() | |
} | |
} | |
} | |
func testCreateDispatchQueue() { | |
printTestName("Create - DispatchQueue") | |
measure { | |
for _ in 0...iterations { | |
_ = DispatchQueue(label: "test") | |
} | |
} | |
} | |
func testCreateDispatchSemaphore() { | |
printTestName("Create - DispatchSemaphore") | |
measure { | |
for _ in 0...iterations { | |
_ = DispatchSemaphore(value: 1) | |
} | |
} | |
} | |
func testCreateTimeLockSynchronize() { | |
printTestName("Create - LockSynchronize") | |
measure { | |
for _ in 0...iterations { | |
_ = LockSynchronize() | |
} | |
} | |
} | |
func testCreateTimeDispatchQueueSynchronize() { | |
printTestName("Create - DispatchQueueSynchronize") | |
measure { | |
for _ in 0...iterations { | |
_ = DispatchQueueSynchronize() | |
} | |
} | |
} | |
func testCreateTimeDispatchSemaphoreSynchronize() { | |
printTestName("Create - DispatchSemaphoreSynchronize") | |
measure { | |
for _ in 0...iterations { | |
_ = DispatchSemaphoreSynchronize() | |
} | |
} | |
} | |
func testWriteSameThreadLockSynchronize() { | |
printTestName("Write same thread - LockSynchronize") | |
performWriteSameThread(LockSynchronize()) | |
} | |
func testWriteSameThreadDispatchQueueSynchronize() { | |
printTestName("Write same thread - DispatchQueue") | |
performWriteSameThread(DispatchQueueSynchronize()) | |
} | |
func testReadSameThreadLockSynchronize() { | |
printTestName("Read same thread - Lock") | |
performReadSameThread(LockSynchronize()) | |
} | |
func testReadSameThreadDispatchQueueSynchronize() { | |
printTestName("Read same thread - DispatchQueue") | |
performReadSameThread(DispatchQueueSynchronize()) | |
} | |
func testReadWriteRandomThreadsLockSynchronize() { | |
printTestName("Read write random thread - Lock") | |
performReadWriteRandomThread(LockSynchronize()) | |
} | |
func testReadWriteRandomThreadDispatchQueueSynchronize() { | |
printTestName("Read write random thread - DispatchQueue") | |
performReadWriteRandomThread(DispatchQueueSynchronize()) | |
} | |
private func performWriteSameThread(_ synchronize: Synchronize) { | |
let counter = Counter() | |
measure { | |
for _ in 0...iterations { | |
synchronize.write { counter.increment() } | |
} | |
} | |
} | |
private func performReadSameThread(_ synchronize: Synchronize) { | |
let counter = Counter() | |
measure { | |
for _ in 0...iterations { | |
_ = synchronize.read { counter.value } | |
} | |
} | |
} | |
private func performReadWriteRandomThread(_ synchronize: Synchronize) { | |
let iterations = 10000 | |
let expectedValue = 2 * iterations | |
measure { | |
let expect = expectation(description: "Finish") | |
let counter = Counter() | |
for _ in 0..<iterations { | |
DispatchQueue.global(qos: .background).async { | |
synchronize.write { | |
counter.increment() | |
} | |
let value: Int = synchronize.read { | |
counter.increment() | |
return counter.value | |
} | |
if value == expectedValue { expect.fulfill() } | |
} | |
} | |
waitForExpectations(timeout: 60) { _ in } | |
} | |
} | |
private func printTestName(_ testName: String) { | |
print("\n") | |
print("****************************************************************") | |
print("\(testName)") | |
print("****************************************************************") | |
} | |
} | |
class Counter { | |
var value: Int = 0 | |
func increment() { | |
value += 1 | |
} | |
} | |
// ----------------------------------------------------------------------------- | |
// Universal protocol | |
// ----------------------------------------------------------------------------- | |
protocol Synchronize { | |
func write(_ closure: @escaping () -> Void) | |
func read<T>(_ closure: @escaping () -> T) -> T | |
} | |
// ----------------------------------------------------------------------------- | |
// Tested implementations | |
// ----------------------------------------------------------------------------- | |
class LockSynchronize: Synchronize { | |
private let lock = NSLock() | |
func write(_ closure: @escaping () -> Void) { | |
lock.lock(); defer { lock.unlock() } | |
closure() | |
} | |
func read<T>(_ closure: @escaping () -> T) -> T { | |
lock.lock(); defer { lock.unlock() } | |
return closure() | |
} | |
} | |
// ----------------------------------------------------------------------------- | |
class DispatchQueueSynchronize: Synchronize { | |
private let queue = DispatchQueue(label: "dispatch_queue_synchronize") | |
func write(_ closure: @escaping () -> Void) { | |
queue.sync { | |
closure() | |
} | |
} | |
func read<T>(_ closure: @escaping () -> T) -> T { | |
return queue.sync { | |
return closure() | |
} | |
} | |
} | |
// ----------------------------------------------------------------------------- | |
class DispatchSemaphoreSynchronize: Synchronize { | |
private let semaphore = DispatchSemaphore(value: 1) | |
func write(_ closure: @escaping () -> Void) { | |
semaphore.wait(); defer { semaphore.signal() } | |
closure() | |
} | |
func read<T>(_ closure: @escaping () -> T) -> T { | |
semaphore.wait(); defer { semaphore.signal() } | |
return closure() | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment