# 은행창구 매니저 PR (step 3) @havilog 안녕하세요 하비! 코낄이, 베토입니다. step3 구현을 다 하고 PR 보냅니다. ## 고민했던 점 & 조언받고 싶은 점 ### 1️⃣ 동시성 구현 방법 선택 이유 Swift에서 동시성을 구현하는 방법으로는 GCD, Operation 두 가지 방법을 고려했습니다. GCD는 Swift의 동시성 구현 방법으로 가장 먼저 등장한 기본적인 방법이고, Operation은 GCD를 기반으로 더 객체지향적으로 등장한 개념이라고 합니다. 저희는 동시성 프로그래밍의 개념을 처음 접하기 때문에, 가장 기본적인 GCD를 활용한 방법으로 구현해보았습니다. ### 2️⃣ 총 업무시간 산출 방법 변경 저희는 총 인원을 `numberOfClient`라는 변수에 `clientQueue`가 `dequeue` 될 때마다 늘려주고 최종적인 인원이 `numberOfClient`에 들어가면 `numberOfClient` 변수에 `0.7`을 곱한 숫자를 총 업무시간으로 출력하였습니다. 하지만 step3의 동시성 프로그래밍을 하면서 기존의 산출 방법으로 동시에 수행되는 작업들의 총 업무시간을 나타내기엔 힘든 부분이 있었습니다. 따라서 현재는 `Foundation` 내장 함수인 `CFAbsoluteTimeGetCurrent()`을 활용하여 작업을 수행하기 전에 시간을 구해주고 작업이 전부 끝난 뒤 시간을 구하여 그 차이를 나타내는 식으로 코드를 작성하였습니다. ```swift private func measureProcessTime(_ process: () -> ()) -> Double { let startTime = CFAbsoluteTimeGetCurrent() process() let processTime = CFAbsoluteTimeGetCurrent() - startTime return processTime } ``` ### 3️⃣ Banker 타입의 인스턴스가 불필요했던 점 이번 스텝에서 3명의 은행원이 근무하고 2명은 예금업무를, 1명은 대출업무를 수행하도록 하는 요구사항이 있었습니다. 요구사항에 따라 직관적으로 `Bank` 타입 내에 `bankers: [Banker]` 프로퍼티를 구현하는 방법으로 접근하려고 했습니다. 그런데 GCD를 활용하여 동시성을 구현하다 보니 **`businessQueue: DispatchQueue` 에 의해 관리되는 스레드 자체가 은행원의 역할을 수행**한다고 생각하게 되었습니다. ``` swift final class Bank { private var clientQueue: Queue<BankClient> = .init() private var numberOfClient: Int = 0 private let businessQueue: DispatchQueue = .init(label: "bankerDispatchQueue", attributes: .concurrent) private let depositSemaphore: DispatchSemaphore = .init(value: 2) private let loanSemaphore: DispatchSemaphore = .init(value: 1) ... } ``` `DispatchSemaphore` 타입의 프로퍼티로 각각의 예금, 대출업무를 수행할 스레드의 수를 제한해주고 `businessQueue`에 dispatch 해주기만 하면 알아서 작업이 종료된 스레드에 적절히 분배되는것을 확인했습니다. 따라서 `Banker` 인스턴스가 더이상 필요하지 않게 되었고, 다음과 같이 인스턴스의 생성을 제한하고, 메서드는 타입 메서드로 변경했습니다. ``` swift struct Banker { private init() {} static func receive(client: BankClient) { print("\(client.waitingNumber)번 고객 \(client.businessType.rawValue)업무 시작") Thread.sleep(forTimeInterval: client.businessType.time) print("\(client.waitingNumber)번 고객 \(client.businessType.rawValue)업무 완료") } } ```