Concurrency Programming, ๋์์ฑ ํ๋ก๊ทธ๋๋ฐ
- ๋์์ฑ ํ๋ก๊ทธ๋๋ฐ์ ์ฌ๋ฌ ๊ฐ์ ์ค๋ ๋๋ฅผ ์ด์ฉํ์ฌ ๋์์ ์ฌ๋ฌ ์์ ์ ์ฒ๋ฆฌํฉ๋๋ค.
- ๋์์ฑ ํ๋ก๊ทธ๋๋ฐ์ ์ฑ๊ธ ์ฝ์ด์์๋ ๊ฐ๋ฅํ ๋ ผ๋ฆฌ์ ์ธ ๊ฐ๋ ์ ๋๋ค.
- Swift๋ก ๋์์ฑ ํ๋ก๊ทธ๋๋ฐ์ ๊ตฌํํ๋ ๋ฐฉ๋ฒ์ผ๋ก๋ completion handler, GCD, Operation, Structed Concurrency๊ฐ ์๋ค
Parallel Programming, ๋ณ๋ ฌ ํ๋ก๊ทธ๋๋ฐ
- ๋ณ๋ ฌ ํ๋ก๊ทธ๋๋ฐ์ ์ฌ๋ฌ ๊ฐ์ CPU(์ฝ์ด)๊ฐ ํ๋์ ์์ (Task)์ ๋ถ๋ดํด์ ์ฒ๋ฆฌํ๋ ๊ฒ
- ๋ฌผ๋ฆฌ์ ์ธ ๊ฐ๋ ์ผ๋ก CPU(์ฝ์ด)๊ฐ ์ฌ๋ฌ ๊ฐ ์์ ๋์ ๊ฐ๋ฅ
- ๋ณ๋ ฌ ํ๋ก๊ทธ๋๋ฐ์ ๋ค์ค ์ฝ์ด๋ฅผ, ๋์์ฑ ํ๋ก๊ทธ๋๋ฐ์ ๋ค์ค ์ค๋ ๋๋ฅผ ํ์ฉํ๋ ๊ฒ์ด๋ฉฐ ์ด ๋์ ๋์์ ์ผ์ด๋ ์๋ ์์ต๋๋ค.
Serial Programming, ์ง๋ ฌ์ฑ ํ๋ก๊ทธ๋๋ฐ
- ์ง๋ ฌ์ฑ ํ๋ก๊ทธ๋๋ฐ์ ๋จ ํ๋์ ์ค๋ ๋์์๋ง ์์ ์ ํ๋ ๊ฒ์ ๋๋ค.
- ๋์์ ์์ ์ ์ฒ๋ฆฌํ์ง ๋ชปํ๊ณ , ์์๋๋ก ์์ ์ ์ฒ๋ฆฌํด์ผํฉ๋๋ค.
Synchronous, ๋๊ธฐ
- ๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ์ ์์ ์ด ๋๋๊ธฐ๋ฅผ ๊ธฐ๋ค๋ฆฌ๋ ๊ฒ์ ๋๋ค.
- A๋ผ๋ ์ฝ๋ ๋ธ๋ก์ ๋๊ธฐ๋ก ์ฒ๋ฆฌํ๋ค๋ฉด A๋ผ๋ ์ฝ๋์ ์คํ์ด ์์ ํ ๋์ด๋์ผ ๋ค์ ์ฝ๋๋ก ๋์ด๊ฐ๋ค.
Asynchronous, ๋น๋๊ธฐ
- ๋ฐ๋๋ก ๋น๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ์ ์์ ์ด ๋๋๊ธฐ๋ฅผ ๊ธฐ๋ค๋ฆฌ์ง ์๊ณ , ๋ค์ ์ฝ๋ ๋ธ๋ก์ ๋ฐ๋ก ์คํ์ํค๋ ์ฝ๋์ ๋๋ค.
- A, B๋ผ๋ ์์ ์ด ๋์ด๋์ด ์๊ณ A๋ฅผ ๋น๋๊ธฐ ์ฒ๋ฆฌํด์ฃผ์์ ๋ A๋ฅผ ๊ธฐ๋ค๋ฆฌ์ง ์๊ณ ๋ฐ๋ก B ์์ ์ ์์ํ๋ค.
- ๋๊ธฐ์ ๋น๋๊ธฐ๋ ์คํ ์ข ๋ฃ ์์ ์ ์ ์ ์๋๊ฐ์ ๋ํ ์ฐจ์ด๋ก ์ด์ด์ง๋๋ค.
- ๋๊ธฐ๋ก ์ฒ๋ฆฌ๋๋ ์์ ์ ๋ฌด์กฐ๊ฑด ์์ ์ด ์ข ๋ฃ๋๊ธธ ๊ธฐ๋ค๋ฆฌ๊ฒ ๋๋ ์์ ์ด ์ข ๋ฃ๋ ํ์ ํ ์ผ์ ์ ํด์ค ์ ์์ต๋๋ค. ํ์ง๋ง ๋น๋๊ธฐ์ ๊ฒฝ์ฐ์๋ ์ธ์ ์์ ์ด ์ข ๋ฃ๋๋์ง๋ฅผ ์ ์ ์์ต๋๋ค.
๋์์ฑ vs ๋น๋๊ธฐ
- ๋์์ฑ ๋น๋๊ธฐ๋ ์์ ํ ๋ค๋ฅธ ๊ฐ๋
- ๋์์ฑ: Serial์ด๋, Concurrent์ธ๊ฐ๋ ์ค๋ ๋๊ฐ ๋จ์ผ ์ค๋ ๋์ธ๊ฐ, ๋ค์ค ์ค๋ ๋์ธ๊ฐ์ ๊ตฌ๋ถ
- ๋๊ธฐ/๋น๋๊ธฐ: ์ค๋ ๋์ ์์๋ ๋ฌด๊ดํ๊ฒ ์์ ์ด ๋๋๊ธฐ๋ฅผ ๊ธฐ๋ค๋ฆฌ๋, ๊ธฐ๋ค๋ฆฌ์ง ์๋๋์ ๊ตฌ๋ถ
- Serial ํ๊ฒฝ์์ ๋น๋๊ธฐ๋ก ์ฒ๋ฆฌํ ์๋ ์๊ณ , ๋๊ธฐ๋ก ์ฒ๋ฆฌํ ์ ์๊ณ Concurrent ํ๊ฒฝ์์ ๋๊ธฐ๋ก ์ฒ๋ฆฌํ ์ ์๊ณ , ๋น๋๊ธฐ๋ก๋ ์ฒ๋ฆฌํ ์ ์๋ค
Grand Central Dispatch (GCD) = Dispatch Framework
Grand Central Dispatch
- Dispatch (=GCD) ๋ ๋ฉํฐ์ฝ์ด ํ๋์จ์ด์์ ๋์์ฑ ์ฝ๋ ์คํ์ ์ํ ์ธ์ด ๊ธฐ๋ฅ, ๋ฐํ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ, ์์คํ ๊ธฐ๋ฅ์ด ํฌํจ๋ ํ๋ ์์ํฌ์ด๋ค.
- Dispatch ํ๋ ์์ํฌ์๋ DispatchQueue, DispatchWorkItem, DispatchGroup, DispatchQoS, DispatchSource, DispatchSemaphore ๋ฑ ๋์์ฑ ํ๋ก๊ทธ๋๋ฐ ์์ ์ฒ๋ฆฌ๋ฅผ ์ํ ๋ค์ํ ํ์ ๋ค์ด ๊ตฌํ๋์ด ์๋ค.
DispatchQueue
- ํ ์คํฌ๋ฅผ ๋จ์ผ ๋๋ ๋ค์ค ์ค๋ ๋์์ ์ง๋ ฌ ๋๋ ๋์ ์คํํ ์ง ๊ด๋ฆฌํ๋ FIFO ํ
- DispatchQueue์ ์์
์ ๋๊ธธ ๋ 2๊ฐ์ง๋ฅผ ์ ํด์ฃผ์ด์ผ ํ๋ค
- ๋จ์ผ ์ค๋ ๋๋ฅผ ์ฌ์ฉํ ๊ฒ์ธ๊ฐ, ๋ค์ค ์ค๋ ๋๋ฅผ ์ฌ์ฉํ ๊ฒ์ธ๊ฐ(Serial/Concurrent)
- ๋๊ธฐ๋ก ์์ ์ ์ฒ๋ฆฌํ ๊ฒ์ธ๊ฐ, ๋น๋๊ธฐ๋ก ์์ ์ ์ฒ๋ฆฌํ ๊ฒ์ธ๊ฐ(sync/async)
- DispatchQueue.main๊ณผ DispatchQueue.global()์ ์ด๋ฏธ ๋ง๋ค์ด์ ธ์๋ ํ๋ก ๊ฐ๊ฐ Serial, Concurrent ํ
// ๋จ์ผ์ค๋ ๋, ๋๊ธฐ
DispatchQueue.main.sync {}
DispatchQueue(label: "Serial").sync {}
// ๋ค์ค ์ค๋ ๋, ๋๊ธฐ
DispatchQueue.global().sync {}
DispatchQueue(label: "Concurrent", attributes: .concurrent).sync {}
// ๋จ์ผ์ค๋ ๋ ๋น๋๊ธฐ
DispatchQueue.main.async {}
DispatchQueue(label: "Serial").async {}
// ๋ค์ค ์ค๋ ๋ ๋น๋๊ธฐ
DispatchQueue.global().async {}
DispatchQueue(label: "Concurrent", attributes: .concurrent).async {}
main Thread
- ์ฑ์ด ์คํ๋๋ ๋์์๋ ๋ ๋ฉ๋ชจ๋ฆฌ์ ์ฌ๋ผ์์๋ ๊ธฐ๋ณธ ์ค๋ ๋๋ก ์ ์ญ์ ์ผ๋ก ์ฌ์ฉ์ด ๊ฐ๋ฅํ๋ค.
- ๋ฉ์ธ ์ค๋ ๋์์ ๋์ํ๋ Run Loop๋ฅผ Main Run Loop๋ผ๊ณ ํ๋ค.
- UIKit์ ๋๋ถ๋ถ์ ์์๋ค์ Thread Unsafe ํ๋ฏ๋ก Race Condition์ด ๋ฐ์ํ ์ ์๋ค.
๋ฐ๋ผ์, ๋ชจ๋ UI ์์ ๋ค์ Serial Queue์ธ Main Thread๋ก ๊ฐ์ ธ์ Main RunLoop์ ๋ฐ๋ผ UI๋ฅผ ๊ทธ๋ฆฌ๋๋ก ํจ/
์ด๋ฌํ ์ฃผ๊ธฐ๋ฅผ View Drawing Cycle ์ด๋ผ๊ณ ํ๋ค. - main ์ค๋ ๋์์ main.sync๋ฅผ ์ง์ ํธ์ถํ๋ฉด ์๋๋ค.
main ์ค๋ ๋๋ Serial Queue์ด๋ฏ๋ก main ์ค๋ ๋๋ main.sync๊ฐ ๋๋๊ธฐ๋ฅผ, main.sync๋ main ์ค๋ ๋์ Block-wait์ด ๋๋๊ธฐ๋ฅผ ๊ธฐ๋ค๋ฆฌ๋ deadlock(๊ต์ฐฉ์ํ) ์ํ๊ฐ ๋์ด๋ฒ๋ฆฌ๊ธฐ ๋๋ฌธ. - main ์ค๋ ๋์ ๋น๋๊ธฐ(async) ์์ ์ ์คํํ๋๊ฒฝ์ฐ, ๋จ์ผ ์ค๋ ๋์์๋ง ์์ ์ด ์ด๋ฃจ์ด์ง๊ณ ์๊ธฐ ๋๋ฌธ์ ๋น๋๊ธฐ ์์ ์ด๋๋ผ๋ ๋์์ ์์ ์ด ์ฒ๋ฆฌ๋์ง๋ ๋ชปํ๊ณ ์์๋๋ก ์์ ์ด ์ฒ๋ฆฌ
DispatchWorkItem
DispatchQueue์์ ์ฝ๋ ๋ธ๋ก์ ํธ์ถํ๋๋ฐ์ ์์ด์ DispatchWorkItem์ ํ์ฉํ์ฌ ์ฝ๋ ๋ธ๋ก์ ์บก์ํ๊ฐ๋ฅ
์ ์๋ DispatchWorkItem๋ sync์ async ๋ฉ์๋์ execute ํ๋ผ๋ฏธํฐ๋ฅผ ํตํด ์ ๋ฌ
let yellow = DispatchWorkItem {
for _ in 1...5 {
print("yellow")
sleep(1)
}
}
let blue = DispatchWorkItem {
for _ in 1...5 {
print("blue")
sleep(1)
}
}
DispatchQueue.main.async(execute: yellow)
DispatchQueue.global().sync(excute: blue)
QoS, Quality of Service
- ๋ฌด์์ ๋ ๋ง์ ๋ฆฌ์์ค๋ฅผ ์ฌ์ฉํ ์ง์ ๋ํ ์ฐ์ ์์ (๋ฌด์์ ๋จผ์ ์ฒ๋ฆฌํ ์ง ์ฐ์ ์์๊ฐ ์๋๋ค)
- ์์คํ ์ QoS ์ ๋ณด๋ฅผ ํตํด ์ค์ผ์ฅด๋ง, CPU ๋ฐ I/O ์ฒ๋ฆฌ๋, ํ์ด๋จธ ๋๊ธฐ ์๊ฐ ๋ฑ์ ์ฐ์ ์์๋ฅผ ์กฐ์
- ์ฐ์ ์์๊ฐ ๋์ ์๋ก ๋ ๋ง์ ์ ๋ ฅ์ ์๋ชจ
DispatchGroup
- DispatchGroup์ ๋น๋๊ธฐ์ ์ผ๋ก ์ฒ๋ฆฌ๋๋ ์์ ๋ค์ ๊ทธ๋ฃน์ผ๋ก ๋ฌถ์ด, ๊ทธ๋ฃน ๋จ์๋ก ์์ ์ํ๋ฅผ ์ถ์ ํ ์ ์๋ ๊ธฐ๋ฅ
// ์ฌ์ฉ๋ฐฉ๋ฒ1 : enter, leave๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ
let group1 = DispatchGroup()
group1.enter()
DispatchQueue.main.async {
// ๋น๋๊ธฐ์์
}
DispatchQueue.global().async {
// ๋น๋๊ธฐ์์
}
group1.leave()
// ์ฌ์ฉ๋ฐฉ๋ฒ2 : enter, leave๋ฅผ ์ฌ์ฉํ์ง ์๋ ๊ฒฝ์ฐ
let group2 = DispatchGroup()
DispatchQueue.main.async(group: group2) {
// ๋น๋๊ธฐ์์
}
DispatchQueue.global().async(group: group2) {
// ๋น๋๊ธฐ์์
}
- notify() : notify ๋ฉ์๋์ ์ํด group์ ๋ชจ๋ ์์ ์ด ๋๋๊ธฐ๋ฅผ ๊ธฐ๋ค๋ ธ๋ค๊ฐ ์ฝ๋ ๋ธ๋ก์ ์คํ, ์ด๋ notify์ ํ๋ผ๋ฏธํฐ queue๋ ์ฝ๋๋ธ๋ก์ ์คํ์ํฌ queue๋ฅผ ์ง์
- wait() : wait๋ DispatchGroup์ ์ํ์ด ๋๋๊ธฐ๋ฅผ ๊ธฐ๋ค๋ฆฌ๊ธฐ๋ง ํ๋ ๋ฉ์๋. notify์ ๋ฌ๋ฆฌ ๋ณ๋์ ์ฝ๋ ๋ธ๋ก์ ์คํํ์ง ์์ผ๋ฏ๋ก ์ฝ๋ ๋ธ๋ก์ ์คํ์ํฌ queue๋ฅผ ์ง์ ํ ํ์๋ ์๋ค.
// notify()
let group = DispatchGroup()
DispatchQueue.global().async(group: group, execute: blue)
DispatchQueue.global().async(group: group, execute: red)
group.notify(queue: .main) {
print("๋ชจ๋ ์์
์ด ๋๋ฌ์ต๋๋ค.")
}
// wait()
let group = DispatchGroup()
DispatchQueue.global().async(group: group, execute: blue)
DispatchQueue.global().async(group: group, execute: red)
group.wait()
print("๋ชจ๋ ์์
์ด ๋๋ฌ์ต๋๋ค.")
DispatchSemaphore
- ์ค๋ ๋์ ์ ๊ทผ๊ฐ๋ฅํ ์ค๋ ๋ ์๋ฅผ ์ค์ Race Condition์ ๋ฐฉ์ง
- wait()๊ณผ signal()์ ํธ์ถํ์ฌ ์ ๊ทผ๊ถํ ์์ฒญ๋ฐ ๋ฐํ
Operation
Operation
- ์คํํ ์ฝ๋ ๋ธ๋ก์ ๊ฐ์ฑํํด๋ ๊ฒ. (GCD์ DispatchWorkItem์ ์ ์ฌ)
- Operation์ ์ถ์ํด๋์ค์ด๋ฏ๋ก ํ์ ํด๋์ค๋ ์ปค์คํ ํด๋์ค๋ก ์ง์ ๋ง๋ค์ด์ฃผ๊ฑฐ๋ BlockOperation์ด๋ผ๋ ํ์ ํด๋์ค๋ฅผ ์ฌ์ฉ
- Opertion์ ์คํํ๋ ๋ฐฉ๋ฒ์ ํฌ๊ฒ 2๊ฐ์ง
- ์ง์ ์คํ
- OperationQueue์ ๋ฃ๋ ๋ฐฉ๋ฒ
let operation = BlockOperation {
// A. some code
}
// BlockOperation์ ๋ฉ์๋
operation.addExecutionBlock {
// B.Operation์ ๋์์ด ๋๋๊ณ ๋ ํ์ ์ํ๋ ์ฝ๋๋ฅผ ์คํ A->B
}
// Operation์ ํ๋กํผํฐ
operation.completionBlock = {
// C. Operation๊ณผ ๊ทธ์ ์ฐ๊ด๋ executionBlock๋ค์ด ๋ชจ๋ ์คํ๋ ๋ค์์ ์คํ A->B->C
}
// OperationQueue์๋ Operation์ ๋ฃ์ด์ฃผ๊ธฐ๋ง ํ๋ฉด ๋ฐ๋ก ์คํ๋๋ค
let operationQueue = OperationQueue()
operationQueue.addOperation(operation)
OperationQueue
- OperationQueue๋ Operation ๊ฐ์ฒด๋ค์ ์คํํ๊ณ ๊ด๋ฆฌํ๋ ๋๊ธฐ์ด
- Operation๊ฐ์ ๊ฒฝ์ฐ๋ ์ข ๋ ๊ฐ์ฒด์งํฅ์ ์ผ๋ก ์ค๊ณ๋์ด sync/async์ ๋ํ ์ ๋ณด๋ Operation์ด ๊ฐ์ง๊ณ ์์ผ๋ฉฐ, ์ค๋ ๋ ๊ด๋ฆฌ๋ OperationQueue๊ฐ ํ๋ค
- operation์ ํ์ ์ถ๊ฐํ๋ฉด ์คํ๋ ๋๊น์ง operation์ ํ์ ๋จ์์๊ณ ์ถ๊ฐ๋ operation์ ์ง์ ์ญ์ ํ ์๋ ์์ต๋๋ค.
- ๋ชจ๋ operation์ด ๋๋ ๋๊น์ง Queue๋ ์ ์ง
GCD vs Operation
- Operation์๋ ํด๋น Operation์ ์ํ๋ฅผ ์ถ์ ํ ์ ์๋ ๋ค์ํ ํ๋กํผํฐ๊ฐ ์กด์ฌ
- isConcurrent: Bool => Operation ๋์์ฑ ์ฌ๋ถ
- isAsynchronous: Bool => Operation ๋น๋๊ธฐ ์ฌ๋ถ
- isReady: Bool => Operation์ด ์คํํ ์ค๋น๋ฅผ ๋ง์น๋ฉด isReady ์ํ๊ฐ ๋ฉ๋๋ค.
- isExecuting: Bool => Start๊ฐ ํธ์ถ๋ ํ(ํน์ OperationQueue์ ์ํด ์คํ๋ ํ) isExecuting ์ํ๊ฐ ๋ฉ๋๋ค.
- isCancel: Bool => Operation์ cancelํ๊ฒ ๋๋ฉด isCancel ์ํ๊ฐ ๋ฉ๋๋ค.
- isFinished: Bool => cancelํ์ง ์๊ณ ๋์์ ๋ชจ๋ ๋ง์ณค๋ค๋ฉด isFinished ์ํ๊ฐ ๋ฉ๋๋ค.
์ฐธ๊ณ
https://medium.com/hcleedev/swift-structed-concurrency%EB%9E%80-32f9a5c7ac58
https://velog.io/@ldh0320/WWDC21-Meet-asyncawait-in-Swift#a-normal-function-call
https://developer.apple.com/documentation/dispatch
https://developer.apple.com/documentation/foundation/operation
https://developer.apple.com/documentation/foundation/operationqueue
'iOS ๐ > iOS' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Module, Library, Framework, XCFramework (0) | 2023.02.03 |
---|---|
async/await, continuation, Actor (0) | 2023.02.01 |
PNG transparency bug report (0) | 2022.12.23 |
Sign in with Apple ํ์คํ(iOS + Node.js) ๊ฐ๋ฐ ๋ ธํธ (0) | 2022.10.12 |
Unable to locate the App Tracking Transparency permission request when reviewed on iOS 15.4.1. (0) | 2022.05.13 |