[Go] goroutine ๊ณผ channel ๋ก API ์คํ ์๊ฐ ๊ฐ์ ํ๊ธฐ
๋ชฉ์ฐจ
- ์๋ก
- ๋๊ธฐ์ ํธ์ถ
- ๋น๋๊ธฐ ํธ์ถ : Goroutine ํ์ฉ
- ๋น๋๊ธฐ ํธ์ถ ๊ฐ์ : Channel ํ์ฉ
- ๊ฒฐ๋ก
์๋ก
์ฌ๋ฌ ํ ํฌ ๊ธฐ์ ์ ๊ธฐ์ ๋ธ๋ก๊ทธ๋ฅผ ์ฝ๊ธฐ ์ข์ํฉ๋๋ค. ๋ค๋ง ๋งค๋ฒ ์ฌ๋ฌ ๋ธ๋ก๊ทธ ํํ์ด์ง๋ฅผ ๋ฐฉ๋ฌธํ๋ค ๋ณด๋ ์์ฃผ ๊ฐ๋ ๋ธ๋ก๊ทธ๋ ๋ฐ๋ก ๋ชจ์์ ์ฝ๊ณ ์ถ์ ์๊ฐ์ด ๋ค๋๋ผ๊ณ ์. ์ด๋ฅผ ์ํด Go๋ฅผ ํ์ฉํ ํ ํฌ ๋ธ๋ก๊ทธ ์คํฌ๋ํผ๋ฅผ ๊ฐ๋ฐํ๊ธฐ๋ก ํ์ต๋๋ค. ์ด๋ฏธ ๊ทธ๋ฐ ์๋น์ค๋ ๋ง์ง ์๋๊ณ ์? ๋ง์ต๋๋ค. ๊ทธ๋๋ ํ๋ฒ ์ง์ ํด๋ณด๊ณ ์ถ์์ต๋๋ค๐.
๊ธฐ์ ์ ๋ธ๋ก๊ทธ๋ค์ ๋ค์ํ ํ๋ซํผ์ ํ์ฉํฉ๋๋ค. Medium ๋ถํฐ ์์ฒด ๋ธ๋ก๊ทธ๋ฅผ ์ด์ํ๋ ๊ณณ๊น์ง, ๋ค์ํ ๋ฐฉ์์ ๊ธฐ์ ๋ธ๋ก๊ทธ๋ฅผ ์ ๊ณตํฉ๋๋ค. ๊ฐ๊ธฐ ๋ค๋ฅธ ํํ์ ํ๋ซํผ์ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ ๊ทธ์ ๋ง๋ ์คํฌ๋ํ ๋ฐฉ์์ ์ฌ์ฉํด์ผ ํฉ๋๋ค. ์ ๋ ๋ธ๋ก๊ทธ ํ๋ซํผ์ ๋ง๋ ์คํฌ๋ํ ๊ตฌํ์ฒด๋ฅผ ๋ง๋ค์ด ์ด๋ฅผ ์ฐจ๋ก๋ก ํธ์ถํ๋ ์์ผ๋ก ์งํํ์ต๋๋ค.
ํ์ฌ๋ ๋ค์ฏ ๊ฐ์ ํ ํฌ ๋ธ๋ก๊ทธ์ ๋ํ ์คํฌ๋ํ ๊ตฌํ์ฒด๋ฅผ ๋ง๋ค์ด ์ฌ์ฉํ๊ณ ์์ง๋ง, ์ถํ์๋ ์ธ๊ตญ์ ํ ํฌ ๋ธ๋ก๊ทธ๋ ๊ฐ์ ธ์ฌ ์ ์๋๋ก ํ์ฅํ ๊ณํ์ ๋๋ค. ์ธ๋ถ API ํธ์ถ์ด 5๊ฐ๋ณด๋ค ๋ ๋ง์์ง ์ ์๋ ์ํฉ์ด์ฃ . ์ง๊ธ์ ๋ค์ฏ ๊ณณ์ API๋ง ํธ์ถํ๊ธฐ์ API๋ฅผ ๋๊ธฐ์์ผ๋ก ํธ์ถํด๋ ๋์ง๋ง, ์์ผ๋ก ๊ทธ ์๊ฐ ๋์ด๋ ๊ฒ์ ๋๋นํด API ๋ฅผ ๋ณ๋ ฌ์ ์ผ๋ก ํธ์ถํ๊ธฐ๋ก ํ์ต๋๋ค. ๋จ์ํ ์ฑ๋ฅ ๊ฐ์ ์ ๋์ด Go ์ธ์ด์ ๊ฐ๋ ฅํ ๋์์ฑ ๋ชจ๋ธ์ ์ค์ ํ๋ก์ ํธ์ ์ ์ฉํด๋ณด๋ ๊ธฐํ๊ฐ ๋ ๊ฒ์ด๋ผ ์๊ฐํ์ต๋๋ค.
์ด ๊ธ์ ๋ค์๊ณผ ๊ฐ์ ํ๋ฆ์ผ๋ก ์งํ๋ฉ๋๋ค:
์ฐ์ ๊ฐ๊ฐ์ API๋ฅผ ๋ธ๋กํน ๋ฐฉ์์ผ๋ก ๊ฐ์ ธ์ค๋ ๊ธฐ์กด ๋ฐฉ์์์, Go ์ธ์ด์ ํน์ง์ธ goroutine
์ ํ์ฉํ ๋น๋๊ธฐ์ API ํธ์ถ, ๊ทธ๋ฆฌ๊ณ channel
์ ํ์ฉํ ์ต์ข
๊ฐ์ ๊น์ง ๋จ๊ณ๋ณ๋ก ์ดํด๋ณด๊ฒ ์ต๋๋ค. ๊ฐ ๋จ๊ณ์์ ์ง๋ฉดํ ๋ฌธ์ ์ ๊ณผ ๊ทธ ํด๊ฒฐ ๊ณผ์ , ๊ทธ๋ฆฌ๊ณ ์ฑ๋ฅ ๊ฐ์ ์ ๊ฒฐ๊ณผ๋ฅผ ๊ตฌ์ฒด์ ์ธ ์ฝ๋์ ํจ๊ป ๋ณด์ฌ๋๋ฆฌ๊ฒ ์ต๋๋ค.
๋๊ธฐ์ ํธ์ถ
๊ฐ ๋ธ๋ก๊ทธ์ ๋ด๋ถ ํธ์ถ ๊ตฌํ์ ์ฌ๊ธฐ์ ๋ณด์ฌ๋๋ฆฌ๊ธฐ์ ๊ธ์ ์ฃผ์ ์ ๊ฑฐ๋ฆฌ๊ฐ ์๋ค๊ณ ์๊ฐ๋์ด ๊นํ ๋ ํฌ๋ก ๋์ฒดํ๊ฒ ์ต๋๋ค.
์ฐ์ ๋๊ธฐ์ ํธ์ถ ๋ถํฐ ์ดํด๋ณด๊ฒ ์ต๋๋ค. ์ฝ๋๋ ๊ฐ๋จํฉ๋๋ค. ๊ฐ ํ ํฌ ๋ธ๋ก๊ทธ์์ ์คํฌ๋ํํ ๋ด์ฉ์ result ๋ฐฐ์ด์ ๋ด์ต๋๋ค. result ๋ฐฐ์ด์ ์คํฌ๋ํ ํ ๋ชจ๋ ํฌ์คํธ๋ฅผ ๋ด๊ณ ์๋ ๋ฐฐ์ด๋ก, ์ถํ์ ํ๋ก ํธ๋จ ๊ฐ๋ฐ ์ ๋ฆฌ์คํฐ์ค ํ ๊ณํ์ ๋๋ค.
result ์ ๋ด์ ํ ํฌ ๋ธ๋ก๊ทธ๋ ์นด์นด์คํ์ด, ์ฌ๋ฆฌ๋ธ์, ๋น๊ทผ, ํ ์ค, ๋ฑ ํฌ์๋ฌ๋๋ก ์ ์ ํ์ต๋๋ค.
type Post struct {
Title string
Url string
Summary string
Date string
Corp compnay.Company
}
func main() {
start := time.Now() // ์์ ์๊ฐ
var result []Post
result = callSynchronous(result)
log.Println("Total :", len(result))
elapsed := time.Since(start) // ๊ฒฝ๊ณผ ์๊ฐ
log.Printf("Execution Time: %s\n", elapsed)
}
// ๋๊ธฐ์ ์ฒ๋ฆฌ
func callSynchronous(result []Post) []Post {
result = append(result, kakaopay.CallApi()...)
result = append(result, oliveyoung.CallApi()...)
result = append(result, daangn.CallApi()...)
result = append(result, toss.CallApi()...)
result = append(result, banksalad.CallApi()...)
return result
}
๋๊ธฐ์ ํธ์ถ ๊ฒฐ๊ณผ ํ์ธ
๋๊ธฐ์ ํธ์ถ์ 3.3์ด๋ฅผ ๊ฑธ์ณ ์๋ฃ๋ ๊ฒ์ ํ์ธํ์ต๋๋ค.
์๋นํ ๋๋ฆฐ๊ฒ์ ๋ณผ ์ ์๋๋ฐ ์ ์๊ฐ์ ํน์ ๋ธ๋ก๊ทธ๋ฅผ ์คํฌ๋ํ ํ ๋ ๋ธ๋กํน์ด ์ค๋ ์กํ๋ ๊ณณ์ด ์๋ ๊ฒ ๊ฐ์ต๋๋ค. ๊ฐ๋ณ ๋ธ๋ก๊ทธ ์คํฌ๋ํ์ ๋ํ ์ฑ๋ฅ ๊ฐ์ ์ ์ถํ์ ์งํํ๋๋ก ํ๊ฒ ์ต๋๋ค.
์ฐ์ ์ 5๊ฐ์ ์ธ๋ถ API ๋ฅผ ๋๊ธฐ์์ผ๋ก ํธ์ถํ ๋ 3.3์ด๊ฐ ๋๋ ์๊ฐ์ด ๊ฑธ๋ฆฐ ๊ฒ์ ํ์ธํ๊ณ , ์ด๋ฅผ ๊ณ ๋ฃจํด์ ํ์ฉํด ๋ณ๋ ฌ์ฒ๋ฆฌ๋ฐฉ์
์ผ๋ก ๊ฐ์ ํ๊ธฐ๋ก ํ์ต๋๋ค.
๊ทธ๋ฆผ์ผ๋ก ํํํ๋ฉด ์๋์ ๊ฐ์ต๋๋ค. ๊ฐ๊ฐ์ ํ ํฌ๋ธ๋ก๊ทธ๋ฅผ ๋๊ธฐ์์ผ๋ก ํธ์ถํ๋ฏ๋ก ํ๋์ ๋ธ๋ก๊ทธ์์ ์คํฌ๋ํ์ด ์๋ฃ๋์ด์ผ ๋ค์ ๋ธ๋ก๊ทธ API ๋ฅผ ํธ์ถํ๋ ๊ฒ์ ๋ํ๋์ต๋๋ค. (๋ธ๋ก๊ทธ์ ํธ์ถ ์์๋ ์์๋ก ์ ์ ํ์ต๋๋ค)
๋น๋๊ธฐ ํธ์ถ : Goroutine ํ์ฉ
๊ณ ๋ฃจํด(Goroutine)์ Go ์ธ์ด์ ๋์์ฑ ํ๋ก๊ทธ๋๋ฐ์ ์ํ ๊ฒฝ๋ ์ฐ๋ ๋์
๋๋ค. ์ผ๋ฐ ์ฐ๋ ๋๋ณด๋ค ํจ์ฌ ์ ์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ฉฐ ๋์์ ์์ฒ ๊ฐ์ ๊ณ ๋ฃจํด์ ์คํํ ์ ์์ด ํจ์จ์ ์ธ ๋์์ฑ ์ฒ๋ฆฌ๊ฐ ๊ฐ๋ฅํฉ๋๋ค. go
ํค์๋๋ฅผ ์ฌ์ฉํ์ฌ ๊ณ ๋ฃจํด์ ์์ฑํ ์ ์๊ณ , ์ด๋ฅผ ํ์ฉํด ๊ธฐ์กด์ ๋๊ธฐ์ ๋ธ๋กํน Api ํธ์ถ์ ๋ณ๋ ฌ์ ์ผ๋ก ์ํํ๋๋ก ๊ฐ์ ํด๋ณด๊ฒ ์ต๋๋ค.
๋ธ๋ก๊ทธ๋ฅผ ์ฐจ๋ก๋ก ํธ์ถํ๋ ๊ธฐ์กด ์ฝ๋์ ๋ค๋ฅด๊ฒ ๊ณ ๋ฃจํด์ ํ์ฉํ ์ฝ๋๋ ์ด์ ๋ณด๋ค ๋ณต์กํด์ก์ต๋๋ค.
func callGoroutine(result []Post) []Post {
// (1)
var mu sync.Mutex
var wg sync.WaitGroup
// (2)
scrapers := []func() []Post{
kakaopay.CallApi,
oliveyoung.CallApi,
daangn.CallApi,
toss.CallApi,
banksalad.CallApi,
}
for _, scraper := range scrapers {
wg.Add(1)
// (3)
go func(scrapeFunc func() []Post) {
defer wg.Done()
// (4)
posts := scrapeFunc()
mu.Lock()
result = append(result, posts...)
mu.Unlock()
}(scraper)
}
// (5)
wg.Wait()
return result
}
์ ํจ์๋ ๋ค์๊ณผ ๊ฐ์ ๋ฐฉ์์ผ๋ก ๋์ํฉ๋๋ค:
(1) sync.Mutex์ sync.WaitGroup์ ์ฌ์ฉํ์ฌ ๋์์ฑ ์ ์ด
(2) ๋ธ๋ก๊ทธ์ ์คํฌ๋ํ ํจ์๋ฅผ scrapers ์ฌ๋ผ์ด์ค์ ์ ์ฅ
(3) ๊ฐ ์คํฌ๋ํ ํจ์์ ๋ํด ๊ณ ๋ฃจํด์ ์์ฑํ์ฌ ๋ณ๋ ฌ๋ก ์คํ
(4) ๊ณ ๋ฃจํด ๋ด์์: ์คํฌ๋ํ ํจ์๋ฅผ ์คํํ์ฌ ๊ฒฐ๊ณผ ๋ฆฌํด
(5) WaitGroup์ ์ฌ์ฉํ์ฌ ๋ชจ๋ ๊ณ ๋ฃจํด์ด ์๋ฃ๋ ๋๊น์ง ๋๊ธฐ
๊ณ ๋ฃจํด์ ํ์ฉํ ๋ณ๋ ฌ ์ฒ๋ฆฌ๋ ๋ชจ๋ API ํธ์ถ์ด ๋์์ ์คํ๋๋ฏ๋ก ์ ์ฒด ์คํ ์๊ฐ์ด ํฌ๊ฒ ๋จ์ถ๋ฉ๋๋ค. ๊ณ ๋ฃจํด์ ํ์ฉํ์ฌ 0.6์ด ๋ง์ ๋ชจ๋ ๋ธ๋ก๊ทธ์ ์คํฌ๋ํ์ ์๋ฃํ๋ฉฐ ์ด์ ์ ๋๊ธฐ์ ์ฒ๋ฆฌ(3.3์ด)์ ๋นํด ์คํ์๊ฐ์ ํฌ๊ฒ ๋จ์ถํ ๊ฒ์ ํ์ธํ ์ ์์์ต๋๋ค.
์ ์ฝ๋๋ก๋ ์ถฉ๋ถํ ๋์ ์ฑ๋ฅ์ ๋ผ ์ ์์ง๋ง ์ด์ง ์์ฌ์ด ๋ถ๋ถ๋ ์กด์ฌํฉ๋๋ค. ๋ฐ๋ก mutex
๋ฅผ ์ฌ์ฉํด ๊ณต์ ์์(result)์ ๋ฝ์ ๊ฑฐ๋ ๋ถ๋ถ์
๋๋ค. ๊ณ ๋ฃจํด์ผ๋ก API ํธ์ถ์ ๋ณ๋ ฌ์ ์ผ๋ก ์คํ๋์ง๋ง ๊ฒฐ๊ณผ๋ฅผ ๊ณต์ ์์์ ๋ด๊ธฐ ์ํด์ mutex ๋ฝ์ ์ฌ์ฉํด์ผ ํฉ๋๋ค. mutex ๋ ๊ณต์ ์์์ ๊ฒฝ์ ์กฐ๊ฑด์ ๋ฐฉ์งํ๋ฉฐ ๋์์ฑ ์ด์๋ฅผ ํด๊ฒฐํ๋ ์ค์ํ ์ญํ ์ ํ์ง๋ง, ๊ฒฐ๊ตญ ๊ฐ๋ณ ๊ณ ๋ฃจํด์ด ๋ธ๋กํน ๋๋ ํจ๊ณผ๋ฅผ ์ด๋ํฉ๋๋ค.
๊ณ ๋ฃจํด์ผ๋ก ๊ฐ์ ํ ํ๋ฆ์ ์์ ๊ทธ๋ฆผ๊ณผ ๊ฐ์ต๋๋ค. 5๊ฐ์ ํ ํฌ๋ธ๋ก๊ทธ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค๊ธฐ ์ํ API ๋ฅผ ๋ชจ๋ ๋ณ๋ ฌ์ ์ผ๋ก ์คํํ๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค.
Go ์ Mutex ๋ ์์๋ณด๊ธฐ
Go ์ ๋ฎคํ ์ค(mutex)๋ ๋์์ฑ ํ๋ก๊ทธ๋๋ฐ์์ ์ค์ํ ๋๊ธฐํ ๋๊ตฌ๋ก, ์ ์ฝ๋์์๋ ์ฌ๋ฌ ๊ณ ๋ฃจํด์ด ๊ณต์ ์์(result)์ ๋์ ์ ๊ทผ ํ๋ ๊ฒ์ ๋ฐฉ์งํฉ๋๋ค. mutex ๋ Lock()์ ํธ์ถํ๋ฉด ๋ฝ์ ํ๋ํ๊ณ , Unlock()์ ํธ์ถํ๋ฉด ๋ฝ์ ํด์ ํฉ๋๋ค. ํ ๋ฒ์ ํ๋์ ๊ณ ๋ฃจํด๋ง ๋ฎคํ ์ค์ ๋ฝ์ ์์ ํ ์ ์์ผ๋ฉฐ, ๋ค๋ฅธ ๊ณ ๋ฃจํด๋ค์ ๋ฝ์ด ํด์ ๋ ๋๊น์ง ๋๊ธฐํฉ๋๋ค.
mu.Lock()๊ณผ mu.Unlock()๋ ๊ฐ๋ณ ๊ณ ๋ฃจํด์ ๋ธ๋กํนํ๋ ๋์์ ๋๋ค. ์ด ์ฝ๋๋ ๋ฉ์ธ ๊ณ ๋ฃจํด์ด ์๋ ๊ฐ ๊ณ ๋ฃจํด์ด result์ ๋ฐ์ดํฐ๋ฅผ ์์ ํ๊ฒ ์ถ๊ฐํ๊ธฐ ์ํด **Mutex(๋ฎคํ ์ค)**๋ฅผ ์ฌ์ฉํด ์ ๊ธ์ ๊ฑธ๊ณ ํด์ ํ๋ ๊ณผ์ ์ ๋๋ค.
mu.Lock():
๊ฐ ๊ณ ๋ฃจํด์ result์ ๋ฐ์ดํฐ๋ฅผ ์ถ๊ฐํ๊ธฐ ์ ์ mu.Lock()์ ํธ์ถํ์ฌ ๋ฎคํ ์ค๋ฅผ ์ ๊ธ๋๋ค.
์ ๊ธ์ด ๊ฑธ๋ฆฐ ๊ณ ๋ฃจํด์ด result๋ฅผ ์ ๋ฐ์ดํธํ๋ ๋์ ๋ค๋ฅธ ๊ณ ๋ฃจํด์ mu.Lock()์์ ๋๊ธฐ(๋ธ๋กํน)ํฉ๋๋ค. ์ฆ, mu.Lock()์ ํธ์ถํ ๊ณ ๋ฃจํด๋ง์ด result์ ์ ๊ทผํ ์ ์๊ณ , ๋ค๋ฅธ ๊ณ ๋ฃจํด์ ๋ฎคํ ์ค๊ฐ ํด์ ๋ ๋๊น์ง ๊ธฐ๋ค๋ ค์ผ ํฉ๋๋ค.
mu.Unlock():
๋ฐ์ดํฐ ์ถ๊ฐ ์์ ์ด ์๋ฃ๋๋ฉด mu.Unlock()์ ํธ์ถํ์ฌ ์ ๊ธ์ ํด์ ํฉ๋๋ค.
๋ค๋ฅธ ๊ณ ๋ฃจํด ์ค ํ๋๊ฐ mu.Lock() ๋๊ธฐ ์ํ์์ ๊นจ์ด๋ result์ ์ ๊ทผํ ์ ์๊ฒ ๋ฉ๋๋ค.
์ฆ ๊ฐ๋ณ ๊ณ ๋ฃจํด์ด ๋ธ๋กํน๋๋ฉด์ ํ ๊ณ ๋ฃจํด์ด mu.Lock()์ ๊ฑธ๊ณ result๋ฅผ ์ ๋ฐ์ดํธํ๋ ๋์, ๋ค๋ฅธ ๊ณ ๋ฃจํด๋ค์ mu.Lock()์์ ๋ธ๋กํน๋์ด, result์ ์ ๊ทผํ์ง ๋ชปํ๊ณ ๋๊ธฐํฉ๋๋ค. ์ด ๋ ๋ฉ์ธ ๊ณ ๋ฃจํด์ ๋ธ๋กํน๋์ง ์์: ๋ฉ์ธ ๊ณ ๋ฃจํด์ wg.Wait()์์ ๋ชจ๋ ๊ณ ๋ฃจํด์ด ์๋ฃ๋๊ธฐ๋ฅผ ๊ธฐ๋ค๋ฆฌ๊ธฐ ๋๋ฌธ์, mu.Lock()๊ณผ ๊ด๋ จ๋ ๋์์๋ ๊ด์ฌํ์ง ์์ต๋๋ค. mu.Lock()๊ณผ mu.Unlock()์ ๊ณ ๋ฃจํด ๊ฐ์ ๊ฒฝ์ ์ํ๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํ ๊ธฐ๋ฒ์ด๋ฉฐ, ๋ฉ์ธ ๊ณ ๋ฃจํด์ด ์ง์ ์ ์ผ๋ก ๋ธ๋กํน๋์ง ์์ต๋๋ค.
๋น๋๊ธฐ ํธ์ถ ๊ฐ์ : channel ํ์ฉ
๊ณ ๋ฃจํด์ ํ์ฉํ๋ฉฐ API ๋ฅผ ๋น๋๊ธฐ ํธ์ถํ์ง๋ง ์์ ๋ฐฉ์์ mutex ๋ฝ์ ์ฌ์ฉํ๋ฏ๋ก ์ผ๋ถ ๊ตฌ๊ฐ์์ ๋ธ๋กํน์ด ๋ฐ์ํ ์ ์์ต๋๋ค.
๋ฎคํ ์ค(mutex)๋ก ๊ณต์ ์์์ ์ ๊ทผ์ ์ ์ดํ๋ ๊ฒ์ ์ผ๋ฐ์ ์ธ ๋ฐฉ๋ฒ์ด์ง๋ง, ์ฌ๋ฌ ๊ณ ๋ฃจํด์ด ๋น๋ฒํ๊ฒ ๊ณต์ ์์์ ์ ๊ทผํ๋ ๊ฒฝ์ฐ์ ๋ฎคํ ์ค๋ก ์ธํ ๋ธ๋กํน์ด ์ ์ฒด ํ๋ก๊ทธ๋จ์ ์ฑ๋ฅ์ ์ ํ์ํฌ ์ ์๋ค๊ณ ์๊ฐํ์ต๋๋ค.
์ด๋ฌํ ์ํฉ์์ Go๋ ์ฑ๋(channel)
์ด๋ผ๋ ๋์์ ์ ๊ณตํฉ๋๋ค.
Go ์ ์ฑ๋์ ๊ณ ๋ฃจํด์ ์ฐ๊ฒฐํด์ฃผ๋ ํต๋ก
์
๋๋ค. ์ฑ๋์ ์๋ฐฉํฅ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํ ์ ์์ผ๋ฉฐ, ์๋ ์ด๋ฏธ์ง์ฒ๋ผ ๊ณ ๋ฃจํด์ ๋์ผํ ์ฑ๋์ ์ด์ฉํด ๋ฐ์ดํฐ๋ฅผ ๊ตํํ ์ ์์ต๋๋ค.
์ฑ๋์ ์ฌ์ฉํ๋ฉด ๊ฐ ๋ฐ์ดํฐ๋ฅผ ๊ฐ๋ณ ๊ณ ๋ฃจํด์์ ์ฒ๋ฆฌํ๊ณ ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ์ฑ๋์ ํตํด ์ ์กํฉ๋๋ค. ๋ฉ์ธ ๊ณ ๋ฃจํด์ ์ฑ๋์์ ๊ฒฐ๊ณผ๋ฅผ ์์งํฉ๋๋ค. ๊ฒฐ๊ตญ ๊ณต์ ์์์ ๋ํ ๋ชจ๋ ์ ๊ทผ์ ๋จ์ผ ๊ณ ๋ฃจํด์ผ๋ก ๊ด๋ฆฌํ ์ ์๊ธฐ์, ์ฑ๋์ ์ฌ์ฉํ๋ฉด ๋ณต์กํ ๋๊ธฐํ ๋ก์ง ์์ด๋ ๊ณ ๋ฃจํด ๊ฐ์ ์์ ์ ์กฐ์จํ ์ ์์ต๋๋ค.
* ๐ ๊ทธ๋ ๋ค๊ณ ์ฑ๋์ด ๋ฎคํ ์ค๋ฅผ ์์ ํ ๋์ฒดํ ์ ์๋จ ์๋ฏธ๋ ์๋๋๋ค. ์ฑ๋์ ์ฃผ๋ก ๊ณ ๋ฃจํด ๊ฐ์ ํต์ ๊ณผ ์์ ์กฐ์จ์ ์ฌ์ฉ๋๋ฉฐ, ๋ฎคํ ์ค๋ ์งง์ ์๊ฐ ๋์์ ๊ณต์ ์์ ๋ณดํธ์ ํจ๊ณผ์ ์ ๋๋ค. ๋์ ๊ฐ๊ฐ ์ ์ ํ ์ฌ์ฉํ ๋๊ฐ ์์ผ๋ฉฐ ๋๋ก๋ ๋์ ํจ๊ป ์ฌ์ฉํ๋๊ฒ์ด ํด๊ฒฐ์ฑ ์ด ๋ ์๋ ์๋ค๊ณ ์๊ฐํฉ๋๋ค.
๋ค์์ ์ฑ๋์ ์ด์ฉํด ๊ฐ์ ๋ ์ฝ๋์ ๋๋ค:
func callGoroutineChannel(result []Post) []Post {
scrapers := []func() []Post{
kakaopay.CallApi,
oliveyoung.CallApi,
daangn.CallApi,
toss.CallApi,
banksalad.CallApi,
}
resultChan := make(chan []Post, len(scrapers))
var wg sync.WaitGroup
for _, scraper := range scrapers {
wg.Add(1)
go func(scrapeFunc func() []Post) {
defer wg.Done()
resultChan <- scrapeFunc()
}(scraper)
}
go func() {
wg.Wait()
close(resultChan)
}()
for posts := range resultChan {
result = append(result, posts...)
}
return result
}
1. ๋ฒํผ๋ ์ฑ๋ ์์ฑ
resultChan := make(chan []Post, len(scrapers))
๋ฒํผ์ ํฌ๊ธฐ๋ scarppers ๋ฐฐ์ด์ ๊ธธ์ด๋ก ์ค์ ๋ resultChan ์ฑ๋์ ์์ฑํฉ๋๋ค. ์ด ์ฑ๋์ ๊ฐ ๊ณ ๋ฃจํด์ด ์คํฌ๋ํํ ๊ฒฐ๊ณผ๋ฅผ ์ ๋ฌํ๋ ํต๋ก๋ก ์ฌ์ฉ๋ฉ๋๋ค. ๋ฒํผ๋ ์ฑ๋์ ์ด์ฉํจ์ผ๋ก, ๊ณ ๋ฃจํด์ด ๊ฒฐ๊ณผ๋ฅผ ์ฑ๋์ ์ ์กํ๋ ๊ณผ์ ์์ ๋ธ๋กํน๋์ง ์๋๋ก ํฉ๋๋ค. ๋ฒํผ์ ํฌ๊ธฐ๊ฐ ์ถฉ๋ถํ๋ค๋ฉด, ๊ณ ๋ฃจํด์ด ๊ฒฐ๊ณผ๋ฅผ ์ฆ์ ์ ์กํ๊ณ ์ข ๋ฃ๋ ์ ์์ต๋๋ค.
2. ๊ณ ๋ฃจํด์ผ๋ก ๋น๋๊ธฐ ์ฒ๋ฆฌ
๊ฐ ์คํฌ๋ํ ํจ์๋ฅผ ๊ณ ๋ฃจํด์ผ๋ก ๋ณ๋ ฌ ์คํํ๋ฉฐ, ๊ฐ ๊ณ ๋ฃจํด์ ์คํฌ๋ํ ๊ฒฐ๊ณผ๋ฅผ resultChan์ ์ ๋ฌํฉ๋๋ค. ๋ชจ๋ ๊ณ ๋ฃจํด์ด ์๋ฃ๋๋ฉด WaitGroup์ ์ฌ์ฉํด ๊ฐ๋ณ ๊ณ ๋ฃจํด์ ์์ ์ด ๋๋ฌ๋์ง ํ์ธํ ์ ์์ต๋๋ค.
3. ์ฑ๋ ์์ ๋ฐ ๊ฒฐ๊ณผ ์์ง
for posts := range resultChan
๊ตฌ๋ฌธ์ ํตํด ์ฑ๋์์ ๊ฒฐ๊ณผ๋ฅผ ์์ฐจ์ ์ผ๋ก ์์ ํฉ๋๋ค. ์ฑ๋์ด ๋ซํ ๋๊น์ง ์ด ๋์์ด ๋ฐ๋ณต๋๋ฉฐ, ์ฑ๋์ด ๋ซํ๋ฉด for ๋ฃจํ๋ ์ข
๋ฃ๋ฉ๋๋ค. ์ด๋ range ๊ตฌ๋ฌธ์ด <- resultChan
๊ณผ ๋์ผํ ์์ ๋์์ ๋ฐ๋ณต์ ์ผ๋ก ์ฒ๋ฆฌํ๋ ๊ฒ์ผ๋ก ์ดํดํ ์ ์์ต๋๋ค.
4. WatiGroup ๊ณผ ์ฑ๋ ์ข ๋ฃ
๋ณ๋์ ๊ณ ๋ฃจํด์์ wg.Wait()
๋ฅผ ํธ์ถํด, ๋ชจ๋ ๊ณ ๋ฃจํด์ด ์๋ฃ๋ ๋ ์ฑ๋์ close(resultChan)
๋ก ๋ซ์ต๋๋ค. ์ฑ๋์ด ๋ซํ๋ฉด ๋ ์ด์ ์๋ก์ด ๊ฐ์ด ์ ์ก๋์ง ์์ผ๋ฉฐ, ์ฑ๋์ ๋ฐ์ดํฐ๋ ์์ ํ๊ฒ ๋ชจ๋ ์ฒ๋ฆฌ๋ฉ๋๋ค.
channel ์ ์ฌ์ฉํ ๊ฒฐ๊ณผ๋ 0.5์ด๋ก mutex ๋ฅผ ์ฌ์ฉํ ๋ฐฉ์๊ณผ ๋น๊ตํ์ ๋ ์๊ฐ๋ณด๋ค ์ ์๋ฏธํ ๊ฐ์ ์ ์์ต๋๋ค.
ํ์ฌ ํ๋ก์ ํธ ๊ท๋ชจ์์๋ mutex ๋ฝ์ด ์ฑ๋ฅ์ ๊ทธ๋ฆฌ ํฐ ์ํฅ์ ๋ฏธ์น๋ค๊ณ ๋ณด๊ธฐ ์ด๋ ค์ธ ์ ๋ ์๊ณ , ๋คํธ์ํฌ ์ง์ฐ ๊ฐ์ ์ธ๋ถ ์์ธ๋ ์์ฌํด ๋ณผ ์ ์์ต๋๋ค. ๊ทธ ์ธ์๋ ๊ฐ ๊ณ ๋ฃจํด ์์ฑ๊ณผ ์ฑ๋ ํต์ ์ ๋ฐ์ํ๋ ์ฝ๊ฐ์ ์ค๋ฒํค๋๋ ๊ณ ๋ คํด๋ณผ์ ์์ต๋๋ค. ์ด๋ ์ค๋ฒํค๋์ ๋ฎคํ ์ค ์ฌ์ฉ ์ ๋ฐ์ํ๋ ์ฑ๋ฅ ์ ํ๊ฐ ํฌ๊ฒ ๋ค๋ฅด์ง ์์ ์ ์๊ธฐ ๋๋ฌธ์, ์์ ์ ๊ท๋ชจ๊ฐ ์๊ฑฐ๋ ๊ณ ๋ฃจํด์์ ์ํํ๋ ์์ ์ด ๊ธธ์ง ์์ ํ์ฌ์ ํ๋ก์ ํธ์์๋ ์ด๋ฐ ์ค๋ฒํค๋๊ฐ ๋ ๋๋๋ฌ์ง ์ ์์ต๋๋ค. ํด๋น ๋ถ๋ถ์ ๊ฐ์ ์ ๋ค์ ํฌ์คํธ์์ ๋ ๋ค๋ค๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
๊ฒฐ๋ก
๋๊ธฐ์ ๋ณด๋ค ๋น๋๊ธฐ์์ด ๋น ๋ฅธ๊ฑด ์ฌ์ค ๋๋ฌด ๋น์ฐํ ์๊ธฐ์ง๋ง ใ ใ ,, ์ด๋ฒ ํ๋ก์ ํธ๋ฅผ ํตํด Go ์ธ์ด์ ๋์์ฑ ๋ชจ๋ธ์ ์ค์ ๋ก ์ ์ฉํด๋ณผ ์ ์์์ต๋๋ค. ์คํฌ๋ํผ ํธ์ถ ๊ณผ์ ์์ ๋๊ธฐ์ ํธ์ถ๋ถํฐ goroutine์ ํ์ฉํ ๋น๋๊ธฐ ์ฒ๋ฆฌ, ๊ทธ๋ฆฌ๊ณ channel์ ์ด์ฉํ ๊ฐ์ ๊น์ง ๋จ๊ณ์ ์ผ๋ก ์ ๊ทผํ๋ฉฐ ๊ฐ ๋ฐฉ์์ ํน์ง์ ์ดํดํ ์ ์์์ต๋๋ค.
Goroutine ์ ์ฌ์ฉํ ๊ฐ๋จํ๊ณ ํจ์จ์ ์ธ ๋์์ฑ์ ๊ตฌํํ ์ ์์๊ณ , mutex ๋ฅผ ์ฌ์ฉํ ๊ณต์ ์์ ์ ๊ทผ ์ ์ด์ ์ค์์ฑ๊ณผ ํ๊ณ๋ฅผ ํ์ ํ์ต๋๋ค. ๋์๊ฐ channel ์ ํ์ฉํด lock ์ ์ ๊ฑฐํ์ฌ ๋์ฑ ์ ์ฐํ๊ณ Go ์ค๋ฌ์ด(?) ๋์์ฑ ์ฒ๋ฆฌ๋ฐฉ์์ ๋ํด์๋ ์๊ฒ ๋์ต๋๋ค.
์ด๋ฒ ๊ธ์์๋ API ํธ์ถ๊ณผ์ ์ ์ ์ง์ ์ผ๋ก ๊ฐ์ ํ๋ ๊ณผ์ ๋ง ๋ค๋ค๋๋ฐ, ์ถํ์๋ ๊ฐ๋ณ ๋ธ๋ก๊ทธ ์คํฌ๋ํ ์ฑ๋ฅ ์ต์ ํ์ ๊ณ ๋ฃจํด๊ณผ ์ฑ๋ ์ฌ์ฉ ์ ์ค๋ฒํค๋ ์ต์ ๋ฐฉ์์ ๋ ๊ณ ๋ คํ ๊ธ์ ์์ฑํด๋ณด๊ฒ ์ต๋๋ค.