ย ย
git checkout step1
LinkedList ์ฝ๋
class Node<T> {
var data: T?
var next: Node<T>?
init(with data: T) {
self.data = data
}
fileprivate init() {
self.data = nil
}
}
struct LinkedList<T> {
private var head: Node<T>
private var tail: Node<T>
var peek: Node<T>? {
return head.next
}
var isEmpty: Bool {
return head === tail
}
init() {
let dummyNode = Node<T>()
head = dummyNode
tail = dummyNode
}
func push(data: T) {
let newNode = Node(with: data)
newNode.next = head.next
head.next = newNode
}
mutating func append(data: T) {
let newNode = Node(with: data)
tail.next = newNode
tail = newNode
}
func contains(_ targetNode: Node<T>) -> Bool {
var currentNode = head
while let nextNode = currentNode.next, nextNode !== targetNode {
currentNode = nextNode
}
return currentNode !== tail
}
mutating func insert(data: T, after targetNode: Node<T>) {
guard self.contains(targetNode) else {
return
}
let newNode = Node(with: data)
newNode.next = targetNode.next
targetNode.next = newNode
if targetNode === tail {
tail = newNode
}
}
mutating func pop() -> Node<T>? {
if self.isEmpty {
return nil
}
let frontNode = head.next
head.next = frontNode?.next
if frontNode === tail {
tail = head
}
return frontNode
}
mutating func removeLast() -> Node<T>? {
if self.isEmpty {
return nil
}
var currentNode = head
while let nextNode = currentNode.next, nextNode !== tail {
currentNode = nextNode
}
let rearNode = tail
tail = currentNode
return rearNode
}
mutating func remove(after targetNode: Node<T>) -> Node<T>? {
guard self.contains(targetNode) else {
return nil
}
let nodeToRemove = targetNode.next
targetNode.next = nodeToRemove?.next
if nodeToRemove === tail {
tail = targetNode
}
return nodeToRemove
}
mutating func clear() {
head.next = nil
tail = head
}
}
Dummy Node
- Dummy Node์ tail์ ํ์ฉํด ๋ง์ง๋ง ๋ ธ๋๊น์ง ํ์ํ๋ ๊ณผ์ ์ ์๋ตํ ์ ์๋๋ก ๊ตฌํํ๋ค. (์๊ฐ๋ณต์ก๋๋ฅผ ๋ฎ์ถค)
- Dummy Node์ Data์ ๋ค์ด๊ฐ ๊ฐ์ ๊ณ ๋ฏผํ๋๋ฐ, data ํ์ ์ ์ต์ ๋๋ก ๋ง๋ฆ์ผ๋ก์จ nil์ด ๋ค์ด๊ฐ ์ ์๋๋ก ํ์๋ค.
ย
Reference Counting
- LinkedList๋ฅผ ํด์ ํ ๋
head.next = nil
๋ก ๋ค์ ๋ ธ๋์ ๋ํ ์ฐธ์กฐ๋ฅผ ํด์ ํ๋ค. ์ด์ ๋ ธ๋๊ฐ ์ฌ๋ผ์ง๋ฉด ๋ค์ ๋ ธ๋์ ์ฐธ์กฐ๊ฐ ์ฌ๋ผ์ ธ ์ฐ์์ ์ผ๋ก ๋ค์ ๋ ธ๋๋ค์ด ํด์ ๋๋ค. - ๋จ, ๋ง์ง๋ง ๋ ธ๋๋ ์ถ๊ฐ์ ์ผ๋ก tail์์์ ์ฐธ์กฐ๋ ์ ๊ฑฐํด ํด์ ํ๋ค. ๋ง์ง๋ง ๋ ธ๋๋ ์ด์ ๋ ธ๋์ tail์ ์ํด ๋ ๋ฒ ์ฐธ์กฐ๋๊ธฐ ๋๋ฌธ์ด๋ค. (ARC์ ๋ํ ์ดํด)
ย
Generics
- Generics ๊ฐ๋ ์ ์ ์ฉํด LinkedList์ ๋ค์ํ ํ์ ์ ๋ด์ ์ ์๋๋ก ๊ตฌํํ๋ค.
ย
- ํ๋ ์ ์ ์ ์ถ(FIFO)์ ํน์ง์ ๊ฐ์ง๋ ADT ์ด๋ค
enqueue()
๋ก ๋ค์ ์ถ๊ฐํ๊ณdequeue()
๋ก ์์์ ๋นผ๋ธ๋ค.enqueue()
,dequeue()
๋ ๋ฐ๋์ ๊ตฌํํด์ผ ํ๋ ๋ฉ์๋์ด๋ฉฐpeek
,isEmpty
,clear
๋ฑ๋ ์ถ๊ฐ์ ์ผ๋ก ๊ตฌํํ ์ ์๋ค.- ํ๋ ๋ฐฐ์ด๋ก๋ ๊ตฌํํ ์ ์์ง๋ง ์ด๋ฒ ํ๋ก์ ํธ์์๋ ์ฐ๊ฒฐ๋ฆฌ์คํธ๋ก ๊ตฌํํ๋ค.
ย
-
ํ ์คํธํ ํ์ ์
setUp()
์์ ์ด๊ธฐํ ํด์คฌ๋ค. -
ํ์ง๋ง ๋ค์ ํ ์คํธ์ฒ๋ผ ํ์ ์ ์๋ก ์์ฑํ๋ ๊ฒฝ์ฐ ํ ์คํธ ํจ์ ๋ด์ given์์ ํ ๋ฒ ๋ ์์ฑ์ ํด์ฃผ์๋ค. ํน์
setUp()
์์ sut์ ๋ค๋ฅธ ์กฐ์์ด ๋ค์ด๊ฐ๊ฒ ๋๋ ๊ฒฝ์ฐ๋ฅผ ๋๋นํด ํ ๋ฒ ๋ ์ด๊ธฐํ๋ฅผ ํจ์ผ๋ก์จ ์ด๋ ํ ๊ฐ๋ ๋ด๊ธฐ์ง ์์๋ค๋ ๊ฒ์ ๋ณด์ฅ&๋ช ์ํ๋ค.func test_ํ๋ฅผ์๋ก์์ฑํ๊ณ _isEmptyํด๋ณด๋ฉด_true์ด๋ค() { //given sut = Queue() //when let outputValue = sut.isEmpty //then XCTAssertTrue(outputValue) }
ย
git checkout step2
Serial
- ํ๋ฒ์ ํ๋๋ง ์ํํ๋ค๋ ๊ฐ๋
- Serial DispatchQueue์ ๋ง์ Task๊ฐ ๋ค์ด๊ฐ ์๋ค๊ณ ํ๋๋ผ๋ ์ด๋ ํ๋์ ์ค๋ ๋์์ ์์ฐจ์ ์ผ๋ก ์ํํ๋ ๊ฒ๊ณผ ๋๊ฐ๋ค.
- ํ์ง๋ง ๋ชจ๋ Task๊ฐ ๊ฐ์ ์ค๋ ๋์์ ์ํ๋๋ ๊ฒ์ ์๋ ์๋ ์๋ค. ๋จ์ง Thread Pool์์ ๊ฐ์ ธ์ค๋ ์ค๋ ๋๋ ํ๋ฒ์ ํ๋๋ฟ์ด๋ค.
Concurrent
- ํ๋ฒ์ ์ฌ๋ฌ๊ฐ๋ฅผ ์ํํ๋ค๋ ๊ฐ๋
- Concurrent DispatchQueue์ ๋ง์ Task๊ฐ ๋ค์ด๊ฐ ์๋ ๊ฒฝ์ฐ ์ด๋ ์ฌ๋ฌ ์ฐ๋ ๋์์ ๋์์ ์ํ๋๊ฒ ๋๋ค
- Thread Pool์์ ๋ช๊ฐ์ ์ฐ๋ ๋๋ฅผ ๊ฐ์ ธ์ฌ์ง๋ ์ ์ ์๋ค.(๋ค๋ง iOS ํ๊ฒฝ์์ ๋ชจ๋ DispatchQueue๊ฐ ๊ฐ์ ธ๋ค๊ฐ ์ฐ๋ ์ฐ๋ ๋ ์ด ํฉ์ 64๊ฐ๋ฅผ ๋์ง ๋ชปํ๋ค.)
ย
Sync
- ๋๊ธฐ ์์ ์๋ฃ์ฌ๋ถ๋ ํธ์ถํ ์ชฝ์์ ์ ๊ฒฝ์ด๋ค.
- ์์ ์ ๋ณด๋ธ ์ชฝ์์ ์ฒ๋ฆฌ๊ฐ ๋๋๊ธฐ๋ฅผ(return) ๊ธฐ๋ค๋ฆฐ๋ค -> ๋ณดํต Blocking
- Non-Blocking์ธ ๊ฒฝ์ฐ ํธ์ถํ ์ชฝ์์ ๋ถํํ ์ผ์ด ๋๋ฌ๋์ง๋ฅผ ๊ณ์ ๋ฌผ์ด๋ณด๊ฒ ๋๋ค
Async
- ๋น๋๊ธฐ ์์ ์๋ฃ์ฌ๋ถ๋ ์ฝ๋ฐฑ์ด ์ ๊ฒฝ์ด๋ค.
- ์์ ์ ๋ณด๋ธ ์ชฝ์์๋ ์์ ์ด ๋๋๊ธฐ๋ฅผ ๊ธฐ๋ค๋ฆฌ์ง ์๋๋ค โ ๋ณดํต Non-Blocking
- Blocking์ธ ๊ฒฝ์ฐ ์์ ์ ๋ถํํ๊ณ ๋์์๋ ์๋ฌด๊ฒ๋ ๋ชปํ๊ธฐ ๋๋ฌธ์ ๋ณดํต ๊ฐ์ด ์ฐ์ด์ง๋ ์๋๋ค.
- ์์ ์ด ๋๋ ๋ค ์ฒ๋ฆฌํ ์ฝ๋๋ฅผ ์ฝ๋ฐฑ์ ๋ฃ์ด๋๊ณ ๋์ํ๋๋ก ํ ์ ์๋ค.
ย
Block
- ํธ์ถ๋ ์ชฝ์ ํจ์๊ฐ ์ ์ด๊ถ์ ๊ฐ์ง๋ฉฐ ์์ ์ด ์๋ฃ๋ ๋๊น์ง ํธ์ถํ ์ชฝ์ด block ๋์ด ์ผ์ ๋ชป ํ๋ค
Non-Block
- ํธ์ถํ ํจ์๊ฐ ์ ์ด๊ถ์ ๊ฐ์ง๊ธฐ ๋๋ฌธ์ block๋์ง ์๋๋ค. ๋๊ธฐ ์์ ์ ๊ฒฝ์ฐ ์์ ์ด ์๋ฃ๋์๋์ง ๊ณ์ ํ์ธํ๋ฉฐ ๋น๋๊ธฐ ์์ ์ ๊ฒฝ์ฐ์๋ ๊ธฐ๋ค๋ฆฌ์ง ์๊ณ ๋ฐ๋ก ๋ค๋ฅธ ์์ ๋ค์ ์ฒ๋ฆฌํ๋ค.
ย
Concurrency
- ๋ ผ๋ฆฌ์ ์ธ ๊ฐ๋
- ์ฌ๋ฌ ์ฐ๋ ๋์ ์์ ์ ๋ถ๋ฐฐํ ๋ค ๋น ๋ฅด๊ฒ ๋ฒ๊ฐ์๊ฐ๋ฉด์ ์ํํ๋ฉด ์ด๋ ๋์์ ์ํ๋๋ ๊ฒ์ฒ๋ผ ๋ณด์ธ๋ค
- ์ด ๋ ์ค๋ ๋๋ ์ํํธ์จ์ด ์ค๋ ๋๋ฅผ ์๋ฏธํ๋ค
Parrellel
- ๋ฌผ๋ฆฌ์ ์ธ ๊ฐ๋
- ์ค์ CPU์ ๋ฌผ๋ฆฌ์ ์ธ ์ฐ๋ ๋๊ฐ ์ฌ๋ฌ๊ฐ ์์ด, ์ฌ๋ฌ ์ผ์ ๋์์ ์ํํ ์ ์๋ค.
- ๋ณ๋ ฌ์ฑ์ ๋์์ฑ์ ํฌํจํ๋ค.
ย
์ํํธ์จ์ด ์ค๋ ๋
- ๊ฐ์ฅ ์์ ์์ ์ ๋จ์, ์คํ์ ๋จ์
- ํ๋ก์ธ์ค ๋ด์์ ์์ฑ๋๋ ๊ฒ์ ์ํํธ์จ์ด ์ค๋ ๋
- ์ํํธ์จ์ด ์ค๋ ๋๋ ๊ฐ์ ํ๋ก์ธ์ค ๋ด ๋ค๋ฅธ ์ค๋ ๋๋ค๊ณผ ์์์ ๊ณต์ ํ๋ค
- ๋ค๋ง ์คํ ์ฃผ์๊ณต๊ฐ๊ณผ PC, Register ๊ฐ์ ๋ณ๋๋ก ๊ฐ์ง๋ค
๋ฌผ๋ฆฌ์ ์ค๋ ๋
- ์ค์ ๋ก CPU๊ฐ ๊ฐ์ง ๊ฒ๋ค์ ๋ฌผ๋ฆฌ์ ์ธ ์ฐ๋ ๋
- ๋ฌผ๋ฆฌ์ ์ธ ์ฐ๋ ๋ ํ๋๋ ์ฌ๋ฌ๊ฐ์ ์ํํธ์จ์ด ์ฐ๋ ๋ ์์ ์ ์ํํ ์ ์๋ค.
- iOS์์๋ Thread Pool์ด๋ผ๋ ๊ฒ์ด ์์ด DispatchQueue๋ ์ด๊ณณ์์ ์ฐ๋ ๋๋ฅผ ๊ฐ์ ธ๋ค๊ฐ ์ด๋ค.(์ํํธ์จ์ด ์ฐ๋ ๋)
ย
sleep(UInt)
๋ฅผ ํธ์ถํด Thread๋ฅผ ์ ์ ์ค์งํ ์ ์๋ค.- Double ํ์
์ ์๊ฐ๋์ Thread๋ฅผ ์ค์งํ๊ณ ์ถ์ ๊ฒฝ์ฐ
Thread.sleep(forTimeInterval:)
๋ฅผ ํ์ฉํ๋ฉด ๋๋ค
ย
- ๋ด๋ถ์ class๋ฅผ ๊ฐ์ง struct๋ฅผ ๋ณต์ฌํ๋ ๊ฒฝ์ฐ ๋ด๋ถ class๋ค์ reference counting์ ๋ชจ๋ ๊ด๋ฆฌํด์ผ ํ๊ธฐ ๋๋ฌธ์ reference counting ์ค๋ฒํค๋๊ฐ ๋ฌด์ฒ ์ปค์ง ์ ์๋ค. ๋ฐ๋ผ์ ์ด๋ฐ ๊ฒฝ์ฐ๋ ์ฐจ๋ผ๋ฆฌ struct๊ฐ ์๋ class๋ก ๊ตฌํํ๋ ๊ฒ์ด ์ข๋ค. ์๋ํ๋ฉด ์์ class์ reference counting๋ง ๊ด๋ฆฌํ๋ฉด ๋๊ธฐ ๋๋ฌธ์ด๋ค. ํ์ง๋ง ์ด๋ฒ ํ๋ก์ ํธ์์ ํ์ ๋ค์ ๋ณต์ฌํ ์ผ์ ์๊ธฐ ๋๋ฌธ์ Node๋ฅผ ์ ์ธํ ํ์ ๋ค์ Struct๋ก ๊ตฌํํ๋ ค๊ณ ํ๋ค.
ย
- DispatchQueue๋ก ๋ณด๋ด๋ closure์์ Struct์ ํ๋กํผํฐ๋ฅผ ์ฐธ์กฐํ๋ ๊ฒฝ์ฐ mutating self๋ฅผ captureํ ์ ์๋ค๋ ์๋ฌ๊ฐ ๋ฐ์ํ๋ค. ๋ฐ๋ผ์ ๋น๋๊ธฐ ์ฒ๋ฆฌ๋ฅผ ํ๋ ํ์ ์ ๊ฒฝ์ฐ class๋ก ๊ตฌํํ๋ค.
struct Camper {
var name: String
mutating func changeName(to newName: String) {
name = "๋ญ๋ก ๋ฐ๊พธ์ฃ ?" //๊ฐ๋ฅํ ๋ฌธ์ฅ
DispatchQueue.global().async {
self.name = "์กฐ์ด!" //๋ถ๊ฐ๋ฅ. ํด๋ก์ ๊ฐ mutableํ self๋ฅผ ์บก์ณํด์ ๊ฐ์ง๊ณ ๋๊ฐ๋ ค ํ๊ธฐ ๋๋ฌธ
}
}
}
ย
git checkout step3
DispatchQueue๋ ๊ฐ๋ฐ์๊ฐ queue์ closure ํํ์ ์์ ์ ์ถ๊ฐํ ์ ์๋๋ก ํ๋ class๋ค. ์์ ์ด queue์ ์ถ๊ฐ๋๋ฉด GCD๋ ์์ ์ ์ฒ๋ฆฌํ๊ธฐ ์ํด ์์์ Thread๋ฅผ ์์ฑํ๊ณ ์์ ์ ๋ณ๋์ thread์ ๋ถ๋ฐฐํด ์ฒ๋ฆฌํ๋ค.
- ํ๋ก๊ทธ๋๋จธ๊ฐ
NSThread
๋ฅผ ๋ง๋ค์ด์ ๋ณต์กํ๊ฒ ๋์์ฑ์ ์ฒ๋ฆฌํ ํ์๊ฐ ์๋๋ก, ์ ํ์์ ์ถ์ํ๋ ํด๋์ค๋ก์จ ์ ๊ณต - ์ฃผ์ํด์ผ ํ ๊ฒ์ DispatchQueue์ Thread๋ ๋ค๋ฅด๋ค๋ ๊ฒ์ด๋ค!
by vivi ๐ฆ
Task - ์คํ๋ ์์ Thread - ์์ ์ด ์คํ๋๋ ํ๋ฆ Queue - ์์ ์คํ์ด ์์ฝ๋ ๋๊ธฐ์ด (์์ฆ ํ์ ์์ ์์ฃผ ๋ณด๋ ํ FIFO ๋ฐฉ์์ ๐)
concurrent / serial - queue๊ฐ ์์ ์ thread์ ํ ๋นํ๋ ๋ฐฉ์์ ๋ํ๋
sync / async - queue์ ์์ ์ ํ ๋น์ํค๋ ๋ฐฉ์
ย
Main
์ฝ๋๊ฐ default๋ก ๋์๊ฐ๋ ๋ฉ์ธ ์ค๋ ๋๋ก ์ ์ผํ ์ค๋ ๋๋ฉฐ serial๋ก ๋์ํ๋ค. UI์ ๊ด๋ จ๋ ์์ ๋ค์ ์ฒ๋ฆฌํ๊ธฐ ๋๋ฌธ์ ๋คํธ์ํฌ ์์ ๊ณผ ๊ฐ์ ๋ง์ ์๊ฐ์ด ์์๋๋ ์์ ์ ๋ค๋ฅธ ์ค๋ ๋์์ ์คํํด ์ต์์ ์ฌ์ฉ์ ๊ฒฝํ์ ์ ๊ณตํ๊ฒ ํ๋ ๊ฒ์ด ์ข๋ค.
-
๋ง์ฝ ๋คํธ์ํฌ ์์ ๊ณผ ๊ฐ์ ์๊ฐ์ด ์ค๋ ๊ฑธ๋ฆฌ๋ ์ผ์ ๋ฉ์ธ์ฐ๋ ๋์์ ์ํ์ํค๊ฒ ํ๋ค๋ฉด ํ๋ฉด์ด ๋ฒ๋ฒ ์ผ ์ ์๋ค. โ Update Cycle์ด ์ง์ฐ๋๊ธฐ ๋๋ฌธ
Global
- ๋น๋๊ธฐ๋ก ์์
์ด ์ฒ๋ฆฌ๋๋ queue. ์๋น์ค ํ์ง(quality of service)์ ๋ฐ๋ผ 6๊ฐ์ง๋ก ๋ถ๋ฅ๊ฐ ๋์ด ์์ผ๋ฉฐ ๊ฐ queue๋ ์ฐ์ ์์๊ฐ ๋์ ์๋ก
๋ ๋ง์ Thread๋ฅผ ๋ฐฐ์นํ๊ณ๋ฐฐํฐ๋ฆฌ๋ฅผ ๋ ์ง์คํด์ ์์ ์ ๋ ๋นจ๋ฆฌ ์ฒ๋ฆฌํ ์ ์๋๋ก ํ๋ค. (qos๋ณ๋ก ํ๊ฐ ์ธ ์ ์๋ ์ฐ๋ ๋์ ๊ฐ์์ ํ์ ์กด์ฌํ์ง ์๋๋ค. ๋ค๋ง ์ฐ๋ ๋ํ๋ก๋ถํฐ ๊ฐ์ ธ์จ ์ํํธ์จ์ด ์ฐ๋ ๋๊ฐ ์ผ๋ง๋ ๋ฌผ๋ฆฌ์ ์ธ ์ฐ๋ ๋(๋๋ CPU)์ ๋ ๋น๋ฒํ ๋ฐฐ์น๋๋์ง๋ ๋ฌ๋ผ์ง๋ค) - .userInteractive, .userInitiated, .default, .utility, .background, .unspecified ๊ฐ ์์ผ๋ฉฐ default๋
DispatchQueue.global()
์ด๋ผ๊ณ ๋ง ๋ช ์ํด์ค๋ ๋๋ค. ๋๋ถ๋ถ์ ๊ฒฝ์ฐ default๋ฅผ ์ฌ์ฉํ๋ค. - qos์ ๋ฐ๋ผ ํ ์ธ์คํด์ค๋ ๋ณ๋๋ก ์์ฑ๋๋ค.
Custom
- ๊ธฐ๋ณธ์ ์ง๋ ฌ๋ก ๋์ํ๋ custom queue
- Concurrentํ๊ฒ ์ค์ ํ ์ ์์ง๋ง ๋์์ฑ queue๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด์๋ ๋ณดํต Global queue๋ฅผ ์ฌ์ฉํ๋ค.
- ์ธ์คํด์ค ์์ฑ ์ label์ ์ง์ ํด ์ค ์ ์๋๋ฐ, ๊ณ ์ identifier๋ก์จ์ ๊ธฐ๋ฅ์ ์ํํ์ง ๋ชปํ๋ค. (๊ฐ์ ๋ ์ด๋ธ๊ฐ์ ์ฃผ์ด ์์ฑํด์ค๋ ์๋ก ๋ค๋ฅธ ํ๋ก ๋ง๋ค์ด์ง)
๐ก
Global ํ์ด๋ Custom ํ์ด๋ ์ด ์ฐ๋ ๋ ๊ฐ์ ์ ํ์ 64๊ฐ์ด๋ค.(iOS ๊ธฐ์ค) ๋ง์ฝ Global์์ ์ด๋ฏธ 64๊ฐ๋ฅผ ์ฐ๊ณ ์๋ค๋ฉด ํ๋ฅผ ์๋ฌด๋ฆฌ ๋ ๋ง๋ค์ด๋ดค์ ํด๋น ํ๋ค์ ์ฐ๋ ๋๋ฅผ ์ธ ์ ์๋ค. ๋ค๋ง ๊ฐ ํ๋ง๋ค ์ฐ๋ ๋ ์ ํ์ ๊ฑธ๋ ค์์ง ์๋ค. (Operation Queue๋ ๊ฐ๋ฅํ๋ค๊ณ ํ๋ค.) ์ฐธ๊ณ
ย
- DispatchQueue์ ๋๊ฒจ์ฃผ๋ Task๋ ํด๋ก์ ์ด๊ธฐ ๋๋ฌธ์ Strong Reference Cycle์ ์ผ๋ํด์ผ ํ๋ค.
- ์ผ๋ฐ์ ์ผ๋ก ํด๋ก์ ๋ด์์ self๋ฅผ ์บก์ฒํ๋ค๊ณ ํด๋, ์ธ์คํด์ค๊ฐ DispatchQueue์ ๋ณด๋ด๋ Taskํด๋ก์ ๋ฅผ ์ฐธ์กฐํ์ง๋ ์๊ธฐ ๋๋ฌธ์ Strong Reference Cycle์ ์๊ธฐ์ง ์๋๋ค. ๊ทธ๋๋ ์ ๋ ํ๋๋ก ํ์.
ย
- ๊ฐ ์ํ์์ ๊ณ ๊ฐ์ ์ ๋ฌด๋ฅผ ๋๊ธฐ์ ์ผ๋ก ์ฒ๋ฆฌํ๋ค. ํ์ง๋ง ๋ง์ฝ ๊ฐ์ ์ ๋ฌด๋ฅผ ์ํํ๋ ์ํ์์ด ๋์ด ์๋ค๋ฉด? ๋น๋๊ธฐ์ ์ธ ์์ ์ ๊ฐ์๋ฅผ ์ ํํ๋ ๋ฐฉ์์ ๊ตฌํํ๊ธฐ ์ํด semaphore ๋ฅผ ์ฌ์ฉํ๋ค.
- Semaphore๋ ์๊ณ๊ตฌ์ญ ๋ฌธ์ ์ ํด๊ฒฐ๋ฐฉ์ ์ค ํ๋๋ก ๋์ผํ ์์์ ๋์์ ์ ๊ทผํ ์ ์๋ ๊ฐ์๋ฅผ ์๋ฏธํ๋ ์ ์ ๋ณ์๋ค. Semaphore๋
wait()
(p์ฐ์ฐ)๊ณผsignal()
(v์ฐ์ฐ) ์ผ๋ก๋ง ์ ๊ทผํ ์ ์์ผ๋ฉฐ semaphore๊ฐ 0์ด๋ฉด ์ ๊ทผ์ ์๋ํ๋ ํ๋ก์ธ์ค๋ ์ค๋ ๋๋ ๋๊ธฐ๋ฅผ ํด์ผ ํ๋ค. - semaphore๊ฐ 0์ด๋ฉด ํ๋ก์ธ์ค๋ ์ค๋ ๋๋
wait()
์์ ๋๊ธฐ๋ฅผ ํ๋ค๊ฐ ์ ๊ทผ์ด ํ์ฉ๋๋ฉด semaphore๋ฅผ 1 ๊ฐ์์ํค๊ณ ์ ๊ทผํ๋ค. ๋ฐ์ดํฐ ์ฌ์ฉ์ด ๋๋๋ฉดsignal()
๋ก semaphore๋ฅผ 1 ์ฆ๊ฐ์์ผ ์ฌ์ฉ์ด ๋๋ฌ์์ ์๋ฆฐ๋ค. - ๊ฐ์ ์
๋ฌด๋ฅผ ํ๋ ์ํ์์ ์๊ฐ 2๋ผ๋ฉด
DispatchSemaphore(value: 2)
๋ฅผ ๋ง๋ค์๋ค. ์ด๋ ๊ฒ ํจ์ผ๋ก์จ DispatchQueue์ ๋์์ ๋ณด๋ผ ์ ์๋ Task์ ์ต๋ ๊ฐ์๋ฅผ ์ ํํ๋ค.
ย
func serveCustomers() {
let tellerGroup = DispatchGroup()
while let currentCustomer = customerQueue.dequeue() {
semaphore.wait()
tellerGroup.enter()
DispatchQueue.global().async {
self.serve(customer: currentCustomer)
self.semaphore.signal()
tellerGroup.leave()
}
}
tellerGroup.wait()
departmentGroup.leave()
}
- DispatchQueue๋ก ๋น๋๊ธฐ ์์
์ ๋ณด๋ผ ๋
semaphore.signal()
๊ณผtellerGroup.leave()
๋ ๊ณผ์ฐ ๋ฉํฐ ์ค๋ ๋ ํ๊ฒฝ์์ ๋์์ ํธ์ถ๋์ ๋ thread safeํ์ง ์๋ฌธ์ด ๋ค์๋ค. Thread์ Semaphore์ ๊ดํ ์คํ ํฌ๋ ๋ํ ๋ฌธ์๋ฅผ ์ฐธ๊ณ ํด๋ณด๋ semaphore์ ์ฐ์ฐ๋ค์atomic
ํ๋ค๊ณ ํ๋ค. ๋ฌธ์์ ๋ฐ๋ฅด๋ฉด ์ด๋ค ์์ ์ดatomic
ํ๋ค๋ ๊ฒ์ ๊ฐ์ ์์ ์ ์๋ํ๋ ๋ค๋ฅธ ์ค๋ ๋์ ์ํด ๋ฐฉํด๋ฐ์ ์ผ์ด ์๋ค. ์ฆ, semaphore์ ์ฐ์ฐ๋ค์thread safe
ํ๋ค. - DispatchSemaphore์ ๊ณต์๋ฌธ์๋ฅผ ๋ณด๋ฉด "efficient implementation of a traditional counting semaphore" ๋ผ๊ณ ์ค๋ช
ํ๊ณ ์์ผ๋ DispatchSemaphore ์ญ์ ์ฐ์ฐ๋ค์ด atomicํ ๊ฒ์ด๋ผ๊ณ ์์ํ๋ค. (
thread safe
ํ ์์ ์ด๋ผ๊ณ ๋ด๋ ์ข์ ๊ฒ ๊ฐ๋ค.) - DispatchGroup์ ๋ํด์๋ ์ฐพ์ง ๋ชปํ์ง๋ง
thread safe
ํ ๊ฒ์ด๋ผ๊ณ ์๊ฐํ๋ค. - DispatchQueue๋ ์์ฒด์ ์ผ๋ก
thread safe
ํ๋ค๊ณ ํ๋ค.
ย
func serveCustomers() {
departments.forEach { _, bankingDepartment in
departmentGroup.enter()
DispatchQueue.global().async {
// ์์
// departmentGroup.leave()
}
}
departmentGroup.wait()
}
- ๋น๋๊ธฐ์ ์ธ ์์
๋ค์ด ๋ชจ๋ ๋๋ ์์ ์ ์๊ณ ์ถ์ด DispatchGroup์ ํ์ฉํ๋ค. ๋น๋๊ธฐ ์์
์ ์์ํ๊ธฐ ์
group.enter()
, ๋น๋๊ธฐ ์์ ์ด ๋๋ ํgroup.leave()
๋ฅผ ํ๋๋ก ํด ์์ ์ ๊ฐ์๋ฅผ ํ์ ํ ์ ์๋๋ก ํ๋ค. ๊ทธ๋ฆฌ๊ณ ๋ง์ง๋ง์ผ๋กgroup.wait()
๋ก group์ ๋ค์ด๊ฐ ์์ ๋ค์ด ๋๋ ๋๊น์ง ๊ธฐ๋ค๋ฆฌ๋๋ก ๊ตฌํํด ์ต์ข ์๋ฃ ์์ ์ ์ ์ ์์๋ค.
ย
-
์ํธ ๋ฐฐ์ ๋ผ๊ณ ํ๋ฉฐ ๊ณต์ ์์์ ์ฌ๋ฌ ์ฐ๋ ๋๊ฐ ์ ๊ทผํ๋ ค ํ๋ ๊ฒ์ ํผํ๊ธฐ ์ํด ์ฌ์ฉ๋๋ค.
-
์ํธ ๋ฐฐ์ ๊ธฐ๋ฒ์๋ ์ฌ๋ฌ๊ฐ์ง๊ฐ ์๋ค.
- ๋ฐ์ปค ์๊ณ ๋ฆฌ์ฆ(์ต์ด)
- ํผํฐ์จ ์๊ณ ๋ฆฌ์ฆ
- Lamport ๋นต์ง ๐ ์๊ณ ๋ฆฌ์ฆ
- ๋ฎคํ ์ค
- ์ธ๋งํฌ์ด
- ๋ชจ๋ํฐ
ย
- BankingCategory๋ ์ํ์์ ์ฒ๋ฆฌํ๋ ์ ๋ฌด์ ์ข ๋ฅ, BankingDepartment๋ ํด๋น ์ ๋ฌด๋ฅผ ์ฒ๋ฆฌํ๋ ๋ถ์๋ฅผ ์ง์นญํ๋ค.
- ํ์ฌ ํ๋ก์ ํธ์๋ loan๊ณผ deposit ๋ ๊ฐ์ง ์
๋ฌด๋ฐ์ ์๊ธฐ ๋๋ฌธ์ Bank์์ ๊ฐ ๋ถ์๋ฅผ ํ๋กํผํฐ๋ก ๊ฐ๊ณ ์์ด๋ ๋์ง๋ง ํ์ฅ์ฑ์ ๊ณ ๋ คํด
[BankingCategory:BankingDepartment]
ํํ์ ๋์ ๋๋ฆฌ๋ก departments(๋ถ์)๋ฅผ ๊ด๋ฆฌํ๋๋ก ํ๋ค. - ์ด๋ฅผ ์ํด ์์ฑ์์์ departments์ ํ์ํ ๊ฐ๋ค์ ๊ฐ๋ณ์ธ์๋ก ๋ฐ๋๋ก ๊ตฌํํ๋ค.
struct Bank {
private var departments = [BankingCategory:BankingDepartment]()
init(departmentInformation: [(departmentCategory: BankingCategory, numberOfDepartmentTellers: Int)]) {
departmentInformation.forEach { category, numberOfTellers in
self.departments[category] = BankingDepartment(duty: category, numberOfBankTellers: numberOfTellers, departmentGroup: self.departmentGroup)
}
}
// ...
}
ย
- ๊ฐ๋ณ์ธ์๋ผ๊ณ ํ๋ฉฐ ํจ์๋ฅผ ํธ์ถํ๋ ์ชฝ์์๋ argument๋ฅผ ์ ์ค์๋, ์ฌ๋ฌ๊ฐ ์ค ์๋ ์๋ค
func someVariadic(numbers: Int...) {
numbers.forEach {
//...
}
}
someVariadic()
someVariadic(1)
someVariadic(1, 2, 3)
-
์ฃผ์ํด์ผ ํ ์
- ๋๊ฒจ์ค ๋ ๋ฐฐ์ด๋ก ๋๊ฒจ์ฃผ์ง ์๋๋ค๋ ๊ฒ
- ๋ฐ์ ์ชฝ์์๋ ๋ฐฐ์ด์ด ๋๋ค๋ ๊ฒ(์์ ๊ฒฝ์ฐ numbers์ ํ์
์
[Int]
์ด๋ค.)
ย
The Basics - The Swift Programming Language (Swift 5.5)
๐ก
Use
UInt
only when you specifically need an unsigned integer type with the same size as the platformโs native word size. If this isnโt the case,Int
is preferred, even when the values to be stored are known to be nonnegative. A consistent use ofInt
for integer values aids code interoperability, avoids the need to convert between different number types, and matches integer type inference, as described in Type Safety and Type Inference.
UInt
๋ ํ๋ซํผ์ ๊ณ ์ word size์ ๋์ผํ ํฌ๊ธฐ์ unsigned integer ํ์ ์ด ํ์ํ ๋์๋ง ์ฌ์ฉํด๋ผ. ๋ง์ฝ ์ด ๊ฒฝ์ฐ๊ฐ ์๋๋ผ๋ฉด,Int
๋ฅผ ์ถ์ฒํ๋ค. (์์ ์ ์๊ฐ๋ง์ ์ ์ฅํ๋ค๊ณ ํ๋๋ผ๋) ์ ์๊ฐ์ ๋ํดInt
ํ์ ์ ์ผ๊ด์ฑ ์๊ฒ ์ฌ์ฉํ๋ค๋ฉด, ์ฝ๋ ์ํธ์ด์ฉ์ฑ์ ์ฆ๋์ํฌ ์ ์์ ๊ฒ์ด๋ค. (๋ค๋ฅธ ์ซ์ ํ์ ๊ฐ์ ๋ณํ๊ณผ์ ์ด ํ์์๊ฒ ๋๋ฉฐ, ์ ์ ํ์ ์ ํ์ ์ถ๋ก ๊ณผ๋ ์ผ์นํ๊ฒ ๋๋ค.)
- ์์ธํ ๋ด์ฉ์ ์ ๋ชจ๋ฅด๊ฒ ์ง๋ง, word size๋ผ๋ ๊ฒ์ ์ปดํจํฐ์ 32-bit, 64-bit ์ํคํ ์ณ๋ฅผ ์๋ฏธํ๋ ๊ฒ์ด๋ฏ๋ก, ํด๋น bit์ ๋์ผํ ์ฌ์ด์ฆ๋ฅผ ๊ฐ์ง๋ unsigned int๊ฐ ํ์ํ ๋๋ง ์ฐ๋ผ๋ ๊ฒ ๊ฐ๋ค. (์ด๊ฑด ๋ ๋ฌด์จ ๋ง์ด์ง)
- Joey ๋ํผ์
-
Int
์UInt
๋ชจ๋word size
๋ฅผ ๊ฐ๋๋ฐ ์ด๋UInt
๋ก ํํํ ์ ์๋ ์์ ๋ฒ์๊ฐInt
๋ณด๋ค ํจ์ฌ ํฝ๋๋ค. ๋ฐ๋ผ์Int
๋ก ํํํ์ง ๋ชปํ๋ ํฌ๊ธฐ์ ์์๋ฅผ ์ ์ธํด์ผํ ๋UInt
๋ฅผ ์ฌ์ฉํ๊ณ ๊ทธ ์ธ์๋Int
๋ฅผ ์ฌ์ฉํ๋ผ๋ ์๋ฏธ์ธ ๊ฒ ๊ฐ์ต๋๋ค. - UInt ๊ณต์๋ฌธ์
- ์ด๋์ ์ด๋ป๊ฒ ํ์ฉํด ๋ณผ ์ ์์๊น?
ย
- ์ผ๋ฐ์ ์ผ๋ก ๊ฐ์ ๋ณ๊ฒฝ์ด ์ถ์ ๋์ง ์๊ธฐ ๋๋ฌธ์ ์ ์ญ๋ณ์๋ ์ฐ์ง ๋ง๋ผ๊ณ ํ๋ค.
- ๊ทธ๋ ๋ค๋ฉด ์ ์ญ์์๋? โ Namespace Pollution์ ๋ง๊ธฐ ์ํด struct, class, enum์ ๋ฃ๋ ๊ฒ์ด ๋ฐ๋์ง ํ ์ ์๋ค.
enum SomeEnum {
static let someGlobalConst = 100
}
- ์ฌ๋ฌ๊ฐ์ง ์ค์์๋ enum์ ๋ฃ๋ ์ด์ ๋ case-less enum์ธ ๊ฒฝ์ฐ accidently ํ๊ฒ instance๋ฅผ initiating ํ ์ผ์ด ์์ผ๋ฏ๋ก!
๐ถ
DispatchQueue
๋ ์ฌ์ค ๋๊ฐ์ ํ๋ก ์ด๋ฃจ์ด์ ธ ์๋ค๊ณ ํฉ๋๋ค.์์ ์ ๋ฐ์๋ค์ด๋ ํ
์์์ ์ ์ฐ๋ ๋๋ก(?) ๋ด๋ณด๋ด๋ ํ
์ด ๋ ๊ฐ๋ก์. ํน์ ์ฐ๋ ๋(์ด๋ฅผํ ๋ฉด ๋ฉ์ธ์ฐ๋ ๋)์์ ๋์ํ๋๋ก ์์ฑํ ์ฝ๋์์ DispatchQueue์ sync๋ก Task๋ฅผ ๋ณด๋ด๋ฉด (์ด๋ ์์ ์ ๋ฐ์๋ค์ด๋ ํ๋ก ๋ค์ด๊ฐ ๊ฒ) ๋น์ฐํ ์์ ์ ๋ณด๋ธ ํด๋น ์ฐ๋ ๋๋ block๋๋ฉด์ ํ์ ๋ณด๋ธ ์์ ์ด ์๋ฃ๋๊ธธ ๊ธฐ๋ค๋ฆฌ๊ฒ ์ฃ ? (์ด Task๋ฅผ ์์ผ๋ก A Task๋ผ๊ณ ์นญํ๊ฒ ์ต๋๋ค.)์ด ๋ sync๋ฅผ ํตํด A Task๋ฅผ ๋ฐ์ DispatchQueu๋
์์ ์ ์ฐ๋ ๋๋ก ๋ด๋ณด๋ด๋ ํ
์ ๋ด๋ณด๋ด๋ ์ผ๋ค(?)์ ๋๊ธฐ์ ์ผ๋ก ์ํํ๋ค๊ณ ํด์. A Task ์ดํ์ ๋ฐ์ ์์ ๋ค์ 'A Task๊ฐ ์ฐ๋ ๋ํ์์ ๊ฐ์ ธ์จ ์ฐ๋ ๋์ ์ํด ์คํ์ด ์๋ฃ'๋์ด์ผ ์คํ์ด ๋ ์ ์๋ ํํ๋ก์. (ํ ์์ฒด๊ฐ Concurrent๋ผ๊ณ ํ๋๋ผ๋ ์ด์๊ฐ์ด ์ํ๋จ) (A Task๋ฅผ ๋ฐ์์ด๋์์ ์ ๋ฐ์๋ค์ด๋ ํ
๋ ๊ทธ๋๋ก ๋๋ฏ๋ก ํด๋น DispatchQueue๋ ๊ณ์ ์์ ์ ๋ฐ์ ์ ์์)๊ทธ๋ฌ๋ฉด A Task๋ฅผ ๋ฐ๊ธฐ ์ด์ ์ ํ์ ์กด์ฌํ๋ Task๋ค์ ์ด๋ป๊ฒ ๋ ๊น? A Task๋ฅผ ๋ฐ๊ธฐ ์ด์ ์ ๋จผ์ ๋ฐ์๋ ์์ ๋ค์ ์ด๋ฏธ ์ฐ๋ ๋ ํ์์ ๊ฐ์ ธ์จ ์ฐ๋ ๋์์ ์คํ์ค์ด๊ฑฐ๋ / ๊ฐ๊น์ด ๋ฏธ๋์ ์ฐ๋ ๋์์ ์คํ๋๊ธฐ๋ฅผ ๊ธฐ๋ค๋ฆฌ๊ณ ์์ ๊ฒ ๊ฐ์ต๋๋ค. A Task์๋ ์๊ด์์ด์. -> ์ ์๊ฐ์ ๋๋ค.
ย
DispatchQueue
๋ ์์ฒด์ ์ผ๋ก thread-safeํ๊ฐ?DispatchSemaphore
๋ ์์ฒด์ ์ผ๋ก thread-safeํ๊ฐ?DispatchGroup
์ ์์ฒด์ ์ผ๋ก thread-safeํ๊ฐ?
โ Step3์ thread-safe์ ํด๋นํ๋ ๋ด์ฉ๋ค๊ณผ ๋์ผํ ๋ด์ฉ์ด๋ค. ์ฐ์ ํ๋ก์ ํธ์ ์ฝ๋ ์งํ ๊ฒฐ๊ณผ๋ก ๋ดค์ ๋์๋ Thread-safeํ ๊ฒ์ผ๋ก ๋ณด์๋ค.
DispatchQueue๋ Thread-Safeํ๋ค.
์ ํ์ ๋์์ฑ ํ๋ก๊ทธ๋๋ฐ ๋ฌธ์
ย ย