Concetti Fondamentali delle Goroutine
Goroutine
Gopher๋ค์๊ฒ golang์ ์ฅ์ ์ ์ด์ผ๊ธฐ ํด๋ฌ๋ผํ๋ฉด ์์ฃผ ๋ฑ์ฅํ๋ ๋์์ฑ(Concurrency) ๊ด๋ จ ๊ธ์ด ์์ต๋๋ค. ๊ทธ ๋ด์ฉ์ ๊ธฐ๋ฐ์ ๊ฐ๋ณ๊ณ ๊ฐ๋จํ๊ฒ ์ฒ๋ฆฌํ ์ ์๋ **๊ณ ๋ฃจํด(goroutine)**์ ๋๋ค. ์ด์ ๋ํ์ฌ ๊ฐ๋ตํ๊ฒ ์์ฑํด๋ณด์์ต๋๋ค.
๋์์ฑ(Concurrency) vs ๋ณ๋ ฌ์ฑ(Parallelism)
๊ณ ๋ฃจํด์ ์ดํดํ๊ธฐ ์ ์, ์์ฃผ ํผ๋๋๋ ๋ ๊ฐ์ง ๊ฐ๋ ์ ๋จผ์ ์ง๊ณ ๋์ด๊ฐ๋ ค ํฉ๋๋ค.
- ๋์์ฑ: ๋์์ฑ์ ๋ง์ ์ผ์ ํ ๋ฒ์ ์ฒ๋ฆฌํ๋ ๊ฒ์ ๊ดํ ๊ฒ์ ๋๋ค. ๊ผญ ์ค์ ๋ก ๋์์ ์คํ๋๋ค๋ ์๋ฏธ๊ฐ ์๋๋ผ, ์ฌ๋ฌ ์์ ์ ์์ ๋จ์๋ก ๋๋๊ณ ๋ฒ๊ฐ์ ๊ฐ๋ฉฐ ์คํํจ์ผ๋ก์จ ์ฌ์ฉ์๊ฐ ๋ณด๊ธฐ์๋ ๋์์ ์ฌ๋ฌ ์์ ์ด ์ฒ๋ฆฌ๋๋ ๊ฒ์ฒ๋ผ ๋ณด์ด๊ฒ ํ๋ ๊ตฌ์กฐ์ , ๋ ผ๋ฆฌ์ ๊ฐ๋ ์ ๋๋ค. ์ฑ๊ธ ์ฝ์ด์์๋ ๋์์ฑ์ ๊ฐ๋ฅํฉ๋๋ค.
- ๋ณ๋ ฌ์ฑ: ๋ณ๋ ฌ์ฑ์ โ์ฌ๋ฌ๊ฐ์ ์ฝ์ด์์ ์ฌ๋ฌ๊ฐ์ ์ผ์ ๋์์ ์ฒ๋ฆฌํ๋๊ฒโ ์ ๋๋ค. ๋ง ๊ทธ๋๋ก ๋ณ๋ ฌ์ ์ผ๋ก ์ผ์ ์งํํ๋ ๊ฒ์ด๋ฉฐ, ๋ค๋ฅธ ์์ ๋ค์ ๋์์ ์คํํฉ๋๋ค.
๊ณ ๋ฃจํด์ Go ๋ฐํ์ ์ค์ผ์ค๋ฌ๋ฅผ ํตํด ๋์์ฑ์ ์ฝ๊ฒ ๊ตฌํํ๊ฒ ํด์ฃผ๋ฉฐ, GOMAXPROCS
์ค์ ์ ํตํด ๋ณ๋ ฌ์ฑ๊น์ง ์์ฐ์ค๋ฝ๊ฒ ํ์ฉํฉ๋๋ค.
ํํ ์ด์ฉ๋ฅ ์ด ๋์ ์๋ฐ์ ๋ฉํฐ์ฐ๋ ๋(Multi thread)๋ ๋ณ๋ ฌ์ฑ์ ๋ํ ๊ฐ๋ ์ ๋๋ค.
๊ณ ๋ฃจํด์ ์ ์ข์๊น?
๊ฐ๋ณ๋ค(lightweight)
์์ฑ๋น์ฉ์ด ๋ค๋ฅธ ์ธ์ด์ ๋นํด์ ๋งค์ฐ ๋ฎ์ต๋๋ค. ์ฌ๊ธฐ์ ์ golang์ ์ ๊ฒ ์ฌ์ฉํ ๊น์? ๋ผ๋ ์๋ฌธ์ด ๋๋๋ฐ ์์ฑ ์์น๊ฐ Go๋ฐํ์ ๋ด๋ถ์์ ๊ด๋ฆฌํ๊ธฐ ๋๋ฌธ์ ๋๋ค. ์๋ํ๋ฉด ์์ ๊ฒฝ๋ ๋ ผ๋ฆฌ ์ค๋ ๋ ์ด๊ธฐ ๋๋ฌธ์ ๋๋ค OS์ฐ๋ ๋ ๋จ์๋ณด๋ค ์๊ณ , ์ด๊ธฐ์คํ์ 2KB์ ๋์ ํฌ๊ธฐ๋ฅผ ํ์๋ก ํ๋ฉฐ ์ฌ์ฉ์์ ๊ตฌํ์ ๋ฐ๋ผ ์คํ์ ์ถ๊ฐํ์ฌ ๋์ ์ผ๋ก ๊ฐ๋ณํ๊ธฐ ๋๋ฌธ์ ๋๋ค.
์คํ ๋จ์๋ก ๊ด๋ฆฌํ์ฌ ์์ฑ,์ ๊ฑฐ๊ฐ ๋งค์ฐ ๋น ๋ฅด๊ณ ์ ๋ ดํ๊ฒ ์ฒ๋ฆฌ๊ฐ ๊ฐ๋ฅํ์ฌ ์๋ฐฑ๋ง๊ฐ์ ๊ณ ๋ฃจํด์ ๋๋ ค๋ ๋ถ๋ด์ค๋ฝ์ง ์์ ์ฒ๋ฆฌ๊ฐ ๊ฐ๋ฅํฉ๋๋ค. ์ด๋ก ์ธํด Goroutine์ ๋ฐํ์ ์ค์ผ์ฅด๋ฌ ๋๋ถ์ OS์ปค๋ ๊ฐ์ ์ ์ต์ํ ํ ์ ์์ต๋๋ค.
์ฑ๋ฅ์ด ์ข๋ค(performance)
์ฐ์ Goroutine์ ์์ ์ค๋ช ์ฒ๋ผ OS์ปค๋ ๊ฐ์ ์ด ์ ์ด ์ฌ์ฉ์ ์์ค(User-Level)์์ ์ปจํ ์คํธ ์ค์์นญ์ ํ ๋ OS์ค๋ ๋ ๋จ์๋ณด๋ค ๋น์ฉ์ด ์ ๋ ดํ์ฌ ๋น ๋ฅด๊ฒ ์์ ์ ์ ํํ ์ ์์ต๋๋ค.
์ธ์๋ M:N๋ชจ๋ธ์ ์ด์ฉํ์ฌ OS์ค๋ ๋์ ํ ๋นํ์ฌ ๊ด๋ฆฌํฉ๋๋ค. OS ์ฐ๋ ๋ ํ์ ๋ง๋ค์ด ๋ง์ ์ฐ๋ ๋๊ฐ ํ์์์ด ์ ์ ์ฐ๋ ๋๋ก๋ ์ฒ๋ฆฌ๊ฐ ๊ฐ๋ฅํฉ๋๋ค. ์๋ฅผ ๋ค์ด ์์คํ ํธ์ถ ๊ณผ ๊ฐ์ ๋๊ธฐ์ํ์ ๋น ์ง๋ฉด Go๋ฐํ์์ OS์ฐ๋ ๋์์ ๋ค๋ฅธ ๊ณ ๋ฃจํด์ ์คํํ์ฌ OS์ฐ๋ ๋๋ ์ฌ์ง ์๊ณ ํจ์จ์ ์ผ๋ก CPU๋ฅผ ํ์ฉํ์ฌ ๋น ๋ฅธ ์ฒ๋ฆฌ๊ฐ ๊ฐ๋ฅํฉ๋๋ค.
์ด๋ก ์ธํ์ฌ Golang์ด ํนํ I/O์์ ์์ ๋ค๋ฅธ ์ธ์ด์ ๋นํด ๋์ ์ฑ๋ฅ์ ๋ผ ์ ์์ต๋๋ค.
๊ฐ๊ฒฐํ๋ค(concise)
๋์์ฑ์ด ํ์ํ ๊ฒฝ์ฐ go
ํค์๋ ํ๋๋ก ํจ์๋ฅผ ์ฝ๊ฒ ์ฒ๋ฆฌํ ์ ์๋๊ฒ๋ ํฐ ์ฅ์ ์
๋๋ค.
Mutex
, Semaphore
๋ฑ ๋ณต์กํ Lock์ ์ด์ฉํด์ผ ํ๋ฉฐ, Lock์ ์ด์ฉํ๋ฉด ํ์์ ์ผ๋ก ๊ณ ๋ ค์ผํ ๋ฐ๋๋ฝ(DeadLock) ์ํ๋ฅผ ๊ณ ๋ คํ ์ ๋ฐ์ ์์ด ๊ฐ๋ฐ์ด์ ์ค๊ณ๋จ๊ณ์์ ๋ถํฐ ๋ณต์กํ ๋จ๊ณ๊ฐ ํ์ํด์ง๋๋ค.
Goroutine์ "๋ฉ๋ชจ๋ฆฌ๋ฅผ ๊ณต์ ํ์ฌ ํต์ ํ์ง ๋ง๊ณ , ํต์ ํ์ฌ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ๊ณต์ ํ๋ผ"๋ ์ฒ ํ์ ๋ฐ๋ผ ์ฑ๋(Channel)
์ ํตํ ๋ฐ์ดํฐ ์ ๋ฌ์ ๊ถ์ฅํ๋ฉฐ SELECT
๋ ์ฑ๋(Channel)๊ณผ ๊ฒฐํฉํ์ฌ ๋ฐ์ดํฐ๊ฐ ์ค๋น๋ ์ฑ๋๋ถํฐ ์ฒ๋ฆฌํ ์ ์๊ฒ ํด์ฃผ๋ ๊ธฐ๋ฅ๊น์ง ์ง์ํฉ๋๋ค. ๋ํ, sync.WaitGroup
์ ์ด์ฉํ๋ฉด ์ฌ๋ฌ ๊ณ ๋ฃจํด์ด ๋ชจ๋ ๋๋ ๋๊น์ง ๊ฐ๋จํ๊ฒ ๊ธฐ๋ค๋ฆด ์ ์์ด ์์
ํ๋ฆ์ ์ฝ๊ฒ ๊ด๋ฆฌํ ์ ์์ต๋๋ค. ์ด๋ฌํ ๋๊ตฌ๋ค ๋๋ถ์ ์ฐ๋ ๋ ๊ฐ์ ๋ฐ์ดํฐ ๊ฒฝ์ ๋ฌธ์ ๋ฅผ ๋ฐฉgi e piรน sicura la gestione della concorrenza.
๋ํ, ์ปจํ ์คํธ(context)๋ฅผ ์ด์ฉํ์ฌ ์ด๋ฅผ ์ฌ์ฉ์ ์์ค(User-Level)์์ ์๋ช ์ฃผ๊ธฐ, ์ทจ์, ํ์์์, ๋ฐ๋๋ผ์ธ, ์์ฒญ๋ฒ์๋ฅผ ์ ์ด ํ ์ ์์ด ์ด๋์ ๋์ ์์ ์ฑ์ ๋ณด์ฅํ ์ ์์ต๋๋ค.
Goroutine์ ๋ณ๋ ฌ ์์ (GOMAXPROCS)
goroutine์ ๋์์ฑ์ด ์ข์์ ์ ๋งํ์ง๋ง ๋ณ๋ ฌ์ ์ง์ํ์ง ์๋? ๋ผ๋ ์๋ฌธ์ด ๋์ค๊ฒ๋๋ค. ์ต๊ทผ CPU์ ์ฝ์ด์์๋ ๊ณผ๊ฑฐ์ ๋ค๋ฅด๊ฒ ๋์๋ฆฌ ์๊ฐ ๋์ด๊ฐ๋ฉฐ, ๊ฐ์ ์ฉ PC๋ํ ์ฝ์ด๊ฐ ์ ์ง์์ ์๊ฐ ๋ค์ด๊ฐ ์๊ธฐ ๋๋ฌธ์ ๋๋ค.
ํ์ง๋ง Goroutine์ ๋ณ๋ ฌ์์
๊น์ง ์งํํฉ๋๋ค ๊ทธ๊ฒ์ด GOMAXPROCS
์
๋๋ค.
GOMAXPROCS
๋ฅผ ์ค์ ํ์ง ์์ผ๋ฉด ๋ฒ์ ๋ณ๋ก ๋ค๋ฅด๊ฒ ์ค์ ๋ฉ๋๋ค.
1.5 ์ด์ : ๊ธฐ๋ณธ๊ฐ 1, 1 ์ด์ ํ์์
runtime.GOMAXPOCS(runtime.NumCPU())
์ ๊ฐ์ ๋ฐฉ์์ผ๋ก ์ค์ ์ด ํ์1.5 ~ 1.24: ์ฌ์ฉ ๊ฐ๋ฅํ ๋ชจ๋ ๋ ผ๋ฆฌ ์ฝ์ด์๋ก ๋ณ๊ฒฝ๋์์ต๋๋ค. ์ด๋๋ถํฐ ๊ฐ๋ฐ์๊ฐ ํฌ๊ฒ ์ ์ฝ์ ํ์ํ ๊ฒฝ์ฐ๊ฐ ์๋๋ฉด ์ค์ ํ ํ์๊ฐ ์์ต๋๋ค
1.25: ์ปจํ ์ด๋ ํ๊ฒฝ์์ ์ ๋ช ํ ์ธ์ด๋ต๊ฒ, linux์์ cGroup์ ํ์ธํ์ฌ ์ปจํ ์ด๋์ ์ค์ ๋
CPU์ ํ
์ ํ์ธํฉ๋๋ค.๊ทธ๋ฌ๋ฉด ๋ ผ๋ฆฌ ์ฝ์ด์๊ฐ 10๊ฐ์ด๊ณ , CPU์ ํ๊ฐ์ด 5์ผ ๊ฒฝ์ฐ
GOMAXPROCS
๋ ๋ ๋ฎ์ ์์ธ 5๋ก ์ค์ ํฉ๋๋ค.
1.25 ์ ์์ ์ ๊ต์ฅํ ํฐ ์์ ์ ์ ๊ฐ์ง๋๋ค. ๋ฐ๋ก ์ปจํ ์ด๋ ํ๊ฒฝ์์์ ์ธ์ด ํ์ฉ๋๊ฐ ์ฌ๋ผ๊ฐ๊ธฐ ๋๋ฌธ์ ๋๋ค. ์ด๋ก ์ธํด์ ๋ถํ์ํ ์ค๋ ๋ ์์ฑ๊ณผ, ์ปจํ ์คํธ ์ค์์นญ์ ์ค์ฌ CPU ์ค๋กํ๋ง(throttling)์ ๋ฐฉ์งํ ์ ์๊ฒ ๋์์ต๋๋ค.
1package main
2
3import (
4 "fmt"
5 "math/rand"
6 "runtime"
7 "time"
8)
9
10func exe(name int, wg *sync.WaitGroup) {
11 defer wg.Done()
12
13 fmt.Printf("Goroutine %d: ์์\n", name) // Goroutine %d: Inizio
14 time.Sleep(10 * time.Millisecond) // ์์
์๋ฎฌ๋ ์ด์
์ ์ํ ์ง์ฐ - Ritardo per la simulazione del lavoro
15 fmt.Printf("Goroutine %d: ์์\n", name) // Goroutine %d: Inizio
16}
17
18func main() {
19 runtime.GOMAXPROCS(2) // CPU ์ฝ์ด 2๊ฐ๋ง ์ฌ์ฉ - Usa solo 2 core CPU
20 wg := sync.WaitGroup();
21 goroutineCount := 10
22 wg.Add(goroutineCount)
23
24 for i := 0; i < goroutineCount; i++ {
25 go exe(i, &wg)
26 }
27
28 fmt.Println("๋ชจ๋ goroutine์ด ๋๋ ๋๊น์ง ๋๊ธฐํฉ๋๋ค...") // Attesa che tutte le goroutine terminino...
29 wg.Wait()
30 fmt.Println("๋ชจ๋ ์์
์ด ์๋ฃ๋์์ต๋๋ค.") // Tutte le operazioni sono state completate.
31
32}
33
Goroutine์ ์ค์ผ์ฅด๋ฌ (M:N๋ชจ๋ธ)
์์ ๋ด์ฉ์ธ M:N๋ชจ๋ธ์ ์ด์ฉํ์ฌ OS์ค๋ ๋์ ํ ๋นํ์ฌ ๊ด๋ฆฌํฉ๋๋ค ๋ถ๋ถ์์ ์กฐ๊ธ ๋ ๊ตฌ์ฒด์ ์ผ๋ก ๋ค์ด๊ฐ๋ฉด goroutine GMP๋ชจ๋ธ์ด ์์ต๋๋ค.
- G (Goroutine): Go์์ ์คํ๋๋ ๊ฐ์ฅ ์์ ์์ ๋จ์
- M (Machine): OS ์ฐ๋ ๋ (์ค์ ์์ ์์น)
- P (Processor): Go๋ฐํ์์ด ๊ด๋ฆฌํ๋ ๋ ผ๋ฆฌ์ ์ธ ํ๋ก์ธ์ค
์ ๋๋ค. P๋ ์ถ๊ฐ์ ์ผ๋ก ๋ก์ปฌ ์คํ ํ(Local Run Queue)๋ฅผ ๊ฐ์ง๋ฉฐ, ํ ๋น๋ G๋ฅผ M์ ๋ฐฐ์ ํ๋ ์ค์ผ์ฅด๋ฌ ์ญํ์ ํฉ๋๋ค. ๊ฐ๋จํ๊ฒ goroutine์
GMP์ ๋์๊ณผ์ ์ ์๋์ ๊ฐ์ต๋๋ค
- G(Gorutine)๊ฐ ์์ฑ๋๋ฉด P(Processor)์ ๋ก์ปฌ ์คํ ํ์ ํ ๋น์ ์งํํฉ๋๋ค
- P(Processor)๋ ๋ก์ปฌ ์คํ ํ์ ์๋ G(Goroutine)์ M(Machine)์ ํ ๋นํฉ๋๋ค.
- M(Machine)์ G(Goroutine)์ ์ํ์ธ block, complete, preempted์ ๋ฐํํฉ๋๋ค.
- Work-Stealing (์์ ํ์น๊ธฐ): ๋ง์ฝ P์ ๋ก์ปฌ ์คํ ํ๊ฐ ๋น๊ฒ ๋ ๊ฒฝ์ฐ, ๋ค๋ฅธ P๋ ๊ธ๋ก๋ฒ ํ๋ฅผ ํ์ธํฉ๋๋ค. ๊ทธ๊ณณ์๋ G(Goroutine)์ด ์๋ค๋ฉด ๋ค๋ฅธ ๋ก์ปฌ P(Processsor)์ ์์ ์ ํ์ณ์ ๋ชจ๋ M์ด ์ฌ์ง ์๊ณ ๋์ํ๋๋ก ๋ง๋ญ๋๋ค.
- ์์คํ ์ฝ ์ฒ๋ฆฌ (Blocking): G(Goroutine)๊ฐ ์คํ์ค Block์ด ๋ฐ์ํ ๊ฒฝ์ฐ M(Machine)์ ๋๊ธฐ์ํ๊ฐ ๋๋๋ฐ, ์ด๋ P(Processor)๋ Block์ด ๋ M(Machine)๊ณผ ๋ถ๋ฆฌํ์ฌ ๋ค๋ฅธ M(Machine)๊ณผ ๊ฒฐํฉํ์ฌ ๋ค์ G(Goroutine)์ ์คํํฉ๋๋ค. ์ด๋ I/O ์์ ๋์ค ๋๊ธฐ์๊ฐ์์๋ CPU๋ญ๋น๊ฐ ์์ต๋๋ค.
- ํ๋์ G(Goroutine)์ด ์ค๋ ์ ์ (preempted)ํ ๊ฒฝ์ฐ ๋ค๋ฅธ G(Goroutine)์๊ฒ ์คํ ๊ธฐํ๋ฅผ ์ค๋๋ค.
Golang์ GC(Garbage Collector)๋ํ Goroutine์์์ ์คํ๋์ด, ์ ํ๋ฆฌ์ผ์ด์ ์ ์คํ์ ์ต์ํ์ผ๋ก ์ค๋จ์ํค๋ฉด์(STW) ๋ณ๋ ฌ์ ์ผ๋ก ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ ๋ฆฌํ ์ ์์ด ์์คํ ์์์ ํจ์จ์ ์ผ๋ก ์ฌ์ฉํฉ๋๋ค.
๋ง์ง๋ง์ผ๋ก Golang์ ์ธ์ด์ ๊ฐํ ์ฅ์ ์ค ํ๋์ด๋ฉฐ, ์ด์ธ์๋ ๋ง์ผ๋ ๋ง์ ๊ฐ๋ฐ์ ๋ถ๋ค์ด ๊ณ ๋ญ์ ์ฆ๊ธฐ์ จ์ผ๋ฉด ์ข๊ฒ ์ต๋๋ค.
๊ฐ์ฌํฉ๋๋ค.