개발 지식/CS 지식

πŸ‘©‍πŸ’» μ™„λ²½νžˆ μ΄ν•΄ν•˜λŠ” 동기/비동기 & λΈ”λ‘œν‚Ή/λ…ΌλΈ”λ‘œν‚Ή

인파_ 2023. 5. 2. 21:25

sync-async

동기/비동기 & λΈ”λ‘œν‚Ή/논블둝킹

ν”„λ‘œκ·Έλž˜λ°μ—μ„œ μ›Ή μ„œλ²„ ν˜Ήμ€ μž…μΆœλ ₯(I/O)을 닀루닀 보면 동기/비동기 & λΈ”λ‘œν‚Ή/λ…ΌλΈ”λ‘œν‚Ή μ΄λŸ¬ν•œ μš©μ–΄λ“€μ„ μ ‘ν•΄λ³Έ κ²½ν—˜μ΄ ν•œλ²ˆ 쯀은 μžˆμ„ 것이닀. λŒ€λΆ€λΆ„ μ‚¬λžŒλ“€μ€ μš©μ–΄λ“€μ΄ λ‚˜νƒ€λ‚΄κ³ μž ν•˜λŠ” ν–‰μœ„μ— λŒ€ν•΄μ„  λ©€ν‹° νƒœμŠ€ν‚Ήκ³Ό λ°€μ ‘ν•œ 관련이 μžˆλ‹€λŠ” 것을 μ•Œκ³  μžˆλ‹€. κ·Έλž˜μ„œ 두 κ°œλ…μ„ λΉ„μŠ·ν•œ κ²ƒμœΌλ‘œ μ˜€ν•΄ν•˜λŠ” μ‚¬λžŒλ“€μ΄ κ½€ λ§Žλ‹€. 😡‍πŸ’«

동기/비동기 와 λΈ”λ‘œν‚Ή/λ…ΌλΈ”λ‘œν‚Ή 이 두 κ°œλ…μ€ ν‘œν˜„ ν˜•νƒœλŠ” λΉ„μŠ·ν•΄ 보일지라도, μ„œλ‘œ λ‹€λ₯Έ μ°¨μ›μ—μ„œ μž‘μ—…μ˜ μˆ˜ν–‰ 방식을 μ„€λͺ…ν•˜λŠ” κ°œλ…μ΄λ‹€. 동기/λΉ„λ™κΈ°λŠ” μš”μ²­ν•œ μž‘μ—…μ— λŒ€ν•΄ μ™„λ£Œ μ—¬λΆ€λ₯Ό μ‹ κ²½ μ¨μ„œ μž‘μ—…μ„ 순차적으둜 μˆ˜ν–‰ν• μ§€ μ•„λ‹Œμ§€μ— λŒ€ν•œ 관점이고,λΈ”λ‘œν‚Ή/논블둝킹은 단어 κ·ΈλŒ€λ‘œ ν˜„μž¬ μž‘μ—…μ΄ block(차단, λŒ€κΈ°) λ˜λŠλƒ μ•„λ‹ˆλƒμ— 따라 λ‹€λ₯Έ μž‘μ—…μ„ μˆ˜ν–‰ν•  수 μžˆλŠ”μ§€μ— λŒ€ν•œ κ΄€μ μ΄λ‹€.

sync-async

이처럼 두 κ°œλ…μ— λŒ€ν•œ 의미 μ°¨μ΄λŠ” λͺ…ν™•ν•˜μ§€λ§Œ, ν”„λ‘œκ·Έλž˜λ°μ—μ„œλŠ” μ’…μ’… ν˜Όμš©λ˜μ–΄ μ‚¬μš©λ˜κΈ°λ„ ν•œλ‹€. λŒ€ν‘œμ μœΌλ‘œ μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ setTimeout() ν•¨μˆ˜λ₯Ό 일반적으둜 비동기 ν•¨μˆ˜λΌκ³ λ§Œ λΆ€λ₯΄μ§€λ§Œ λ™μ‹œμ— λ…ΌλΈ”λ‘œν‚Ή ν•¨μˆ˜μ΄κΈ°λ„ ν•˜λ‹€. 즉, μš°λ¦¬κ°€ νŽΈμ˜μƒ λΆ€λ₯΄λŠ” μžλ°”μŠ€ν¬λ¦½νŠΈ 비동기 ν•¨μˆ˜λŠ” 사싀 비동기 + λ…ΌλΈ”λ‘œν‚Ή ν•¨μˆ˜μΈ 것이닀. λ”°λΌμ„œ 이듀을 μ •ν™•ν•˜κ²Œ κ΅¬λΆ„ν•˜κ³  μ΄ν•΄ν•˜λŠ” 것이 컴퓨터 아킀텍쳐λ₯Ό μ΄ν•΄ν•˜λŠ”λ° μžˆμ–΄ μ€‘μš”ν•˜λ‹€.


동기(Synchronous) / 비동기(Asynchronous)

동기(同期)와 비동기(非同期)λ₯Ό μ•Œμ•„λ³΄κΈ° μ•žμ„œ, 이 두 κ°œλ…μ„ ν•œκΈ€μ΄ μ•„λ‹Œ μ˜λ‹¨μ–΄λ‘œ ν•™μŠ΅ ν•˜κΈΈ κ°•λ ₯히 ꢌμž₯ν•˜λŠ” λ°”λ‹€. μ™œλƒν•˜λ©΄ ν•œκΈ€λ‘œ μ§μ—­ν•˜μžλ©΄ '같은 κΈ°κ°„' λ˜λŠ” '같은 μ£ΌκΈ°'λΌλŠ” 뜻의 ν•œμžλ₯Ό μ‚¬μš©ν•˜λŠ”λ° 였히렀 의미λ₯Ό μ΄ν•΄ν•˜λŠ”λ° μžˆμ–΄ λ”μš± ν˜Όλ™λ§Œ μ£ΌκΈ° λ•Œλ¬Έμ΄λ‹€. κ·Έλž˜μ„œ μ˜λ‹¨μ–΄λ₯Ό 파보자면 Synchronous의 SynλŠ” κ·Έλ¦¬μŠ€μ–΄λ‘œ 'ν•¨κ»˜'μ΄λž€ 뜻이고 chronoλŠ” 'μ‹œκ°„'μ΄λΌλŠ” λœ»μ΄λ‹€.

즉, SynchronousλŠ” μž‘μ—… μ‹œκ°„μ„ ν•¨κ»˜ λ§žμΆ°μ„œ μ‹€ν–‰ν•œλ‹€ λΌλŠ” 뜻으둜 ν•΄μ„λœλ‹€. μž‘μ—…μ„ 맞좰 μ‹€ν–‰ν•œλ‹€λŠ” 말은 μš”μ²­ν•œ μž‘μ—…μ— λŒ€ν•΄ μ™„λ£Œ μ—¬λΆ€λ₯Ό λ”°μ Έ μˆœμ°¨λŒ€λ‘œ μ²˜λ¦¬ν•˜λŠ” 것을 λ§ν•œλ‹€. AsynchronousλŠ” μ•žμ— AλΌλŠ” 접두사가 λΆ™μ–΄ λΆ€μ •ν•˜λŠ” ν˜•νƒœμ΄λ‹€. κ·Έλž˜μ„œ λ™κΈ°μ™€ λ°˜λŒ€λ‘œ μš”μ²­ν•œ μž‘μ—…μ— λŒ€ν•΄ μ™„λ£Œ μ—¬λΆ€λ₯Ό 따지지 μ•ŠκΈ° λ•Œλ¬Έμ— μžμ‹ μ˜ λ‹€μŒ μž‘μ—…μ„ κ·ΈλŒ€λ‘œ μˆ˜ν–‰ν•˜κ²Œ λœλ‹€.

Synchronous-Asynchronous
λ™κΈ°λŠ” μž‘μ—… Bκ°€ μ™„λ£Œλ˜μ–΄μ•Ό λ‹€μŒ μž‘μ—…μ„ μˆ˜ν–‰ν•˜κ³ , λΉ„λ™κΈ°λŠ” μž‘μ—… B의 μ™„λ£Œ μ—¬λΆ€λ₯Ό 따지지 μ•Šκ³  λ°”λ‘œ λ‹€μŒ μž‘μ—…μ„ μˆ˜ν–‰ν•œλ‹€

 

λΉ„λ™κΈ°μ˜ μ„±λŠ₯ 이점

보톡 비동기 νŠΉμ§•μ„ μ΄μš©ν•˜μ—¬ μ„±λŠ₯κ³Ό 연관지어 λ§ν•œλ‹€. μ™œλƒν•˜λ©΄ μš”μ²­ν•œ μž‘μ—…μ— λŒ€ν•˜μ—¬ μ™„λ£Œ μ—¬λΆ€λ₯Ό 신경쓰지 μ•Šκ³  μžμ‹ μ˜ κ·Έλ‹€μŒ μž‘μ—…μ„ μˆ˜ν–‰ν•œλ‹€λŠ” 것은, I/O μž‘μ—…κ³Ό 같은 느린 μž‘μ—…μ΄ λ°œμƒν•  λ•Œ, 기닀리지 μ•Šκ³  λ‹€λ₯Έ μž‘μ—…μ„ μ²˜λ¦¬ν•˜λ©΄μ„œ λ™μ‹œμ— μ²˜λ¦¬ν•˜μ—¬ λ©€ν‹° μž‘μ—…μ„ μ§„ν–‰ν• μˆ˜ 있기 λ•Œλ¬Έμ΄λ‹€. μ΄λŠ” μ „λ°˜μ μΈ μ‹œμŠ€ν…œ μ„±λŠ₯ ν–₯상에 도움을 쀄 수 μžˆλ‹€.

Synchronous-Asynchronous

예λ₯Ό λ“€μ–΄, μ›Ή μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ—μ„œ λ°μ΄ν„°λ² μ΄μŠ€ 쿼리λ₯Ό μˆ˜ν–‰ν•˜λŠ” μž‘μ—…μ΄ μžˆλ‹€κ³  κ°€μ •ν•΄λ³΄μž. 이 μž‘μ—…μ„ 만일 λ™κΈ°μ μœΌλ‘œ μˆ˜ν–‰ν•˜λ©΄, λ°μ΄ν„°λ² μ΄μŠ€μ—μ„œ 응닡이 올 λ•ŒκΉŒμ§€ κΈ°λ‹€λ €μ•Ό ν•œλ‹€. 그러면 이 λ•Œ μ›Ή μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ€ λ‹€λ₯Έ μš”μ²­μ„ μ²˜λ¦¬ν•˜μ§€ λͺ»ν•˜λ―€λ‘œ, λŒ€κ·œλͺ¨ νŠΈλž˜ν”½μ΄ λ°œμƒν•  경우 μ›Ή μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ˜ μ„±λŠ₯이 μ €ν•˜λ  수 μžˆλ‹€. ν•˜μ§€λ§Œ 비동기 λ°©μ‹μœΌλ‘œ λ°μ΄ν„°λ² μ΄μŠ€ 쿼리λ₯Ό μˆ˜ν–‰ν•˜λ©΄, λ°μ΄ν„°λ² μ΄μŠ€μ—μ„œ 응닡이 올 λ•ŒκΉŒμ§€ κΈ°λ‹€λ¦¬λŠ” λ™μ•ˆμ—λ„ λ‹€λ₯Έ μš”μ²­μ„ 'λ™μ‹œμ— 처리'ν•  수 있게 λœλ‹€. μ΄λ ‡κ²Œ 비동기 방식을 μ‚¬μš©ν•˜λ©΄, λŒ€κ·œλͺ¨ νŠΈλž˜ν”½μ—μ„œλ„ μ•ˆμ •μ μœΌλ‘œ λ™μž‘ν•  수 μžˆλŠ” μ›Ή μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ„ λ§Œλ“€ 수 μžˆλ‹€. 

μ—¬κΈ°μ„œ 'λ™μ‹œ 처리' λΌλŠ” κ°œλ…μ€ 두 개 μ΄μƒμ˜ μž‘μ—…μ΄ λ™μ‹œμ— μ‹€ν–‰λ˜λŠ” 것을 의미 ν•œλ‹€. μ΄λŠ” λ©€ν‹° μŠ€λ ˆλ“œλ‚˜ λ©€ν‹° ν”„λ‘œμ„Έμ‹±κ³Ό 같은 λ°©μ‹μœΌλ‘œ κ΅¬ν˜„λ  수 μžˆλ‹€. μžλ°”μŠ€ν¬λ¦½νŠΈ 같은 경우 λΉ„λ™κΈ°λ‘œ μž‘μ—…μ„ μš”μ²­ν•˜λ©΄ λΈŒλΌμš°μ €μ— λ‚΄μž₯된 λ©€ν‹° μŠ€λ ˆλ“œλ‘œ 이루어진 Web API에 μž‘μ—…μ΄ μΈκ°€λ˜μ–΄ 메인 Call Stackκ³Ό μž‘μ—…μ΄ λ™μ‹œμ— 처리되게 λœλ‹€. μ‰½κ²Œ λΉ„μœ ν•˜μžλ©΄ μž‘μ—…μ„ λ°±κ·ΈλΌμš΄λ“œμ— μΈκ°€ν•œλ‹€κ³  μƒκ°ν•˜λ©΄ λœλ‹€. λŒ€ν‘œμ μΈ 비동기 μž‘μ—…μ˜ μ’…λ₯˜λ‘œλŠ” μ• λ‹ˆλ©”μ΄μ…˜ μ‹€ν–‰, λ„€νŠΈμ›Œν¬ 톡신, 마우슀 ν‚€λ³΄λ“œ μž…λ ₯, 타이머 λ“± λ§Žλ‹€. λ‹€λ§Œ μžλ°”μŠ€ν¬λ¦½νŠΈ μ½”λ“œ μ‹€ν–‰ μžμ²΄λŠ” Web APIκ°€ μ•„λ‹Œ Call Stackμ—μ„œ μ‹€ν–‰λœλ‹€.

 

πŸ”„ μžλ°”μŠ€ν¬λ¦½νŠΈ 이벀트 루프 ꡬ쑰 & λ™μž‘ 원리

μžλ°”μŠ€ν¬λ¦½νŠΈ 비동기와 이벀트 루프 λΈŒλΌμš°μ €μ˜ λ©€ν‹° μŠ€λ ˆλ“œλ‘œ μž‘μ—…μ„ λ™μ‹œμ— JavascriptλŠ” μ‹±κΈ€ μŠ€λ ˆλ“œ 언어라고 λ“€μ–΄λ³Έ 적이 μžˆμ„ 것이닀. 'μ‹±κΈ€' μŠ€λ ˆλ“œλΌ ν•œ λ²ˆμ— ν•˜λ‚˜μ˜ μž‘μ—…λ§Œ μˆ˜ν–‰μ΄ κ°€λŠ₯ν•˜

inpa.tistory.com

 

동기와 λΉ„λ™κΈ°λŠ” μž‘μ—… μˆœμ„œ 처리 차이

μœ„μ—μ„œ 동기와 비동기λ₯Ό μš”μ²­ν•œ μž‘μ—…μ— λŒ€ν•΄ μ™„λ£Œ 여뢀에 λŒ€ν•œ 차이라고 λ§ν–ˆμ—ˆλ‹€. 이λ₯Ό μ‰½κ²Œ λ§ν•˜μžλ©΄ μ—¬λŸ¬κ°œμ˜ μš”μ²­ μž‘μ—…μ„ 순차적으둜 μ²˜λ¦¬ν•˜λŠλƒ μ•„λ‹ˆλƒμ— λ”°λ₯Έ 차이둜 보면 λœλ‹€. μš”μ²­ν•œ μž‘μ—…μ— λŒ€ν•œ μ™„λ£Œ μ•Œλ¦Όμ„ λ°˜λ“œμ‹œ λ°›μ•„μ•Ό λ‹€μŒ μž‘μ—…μ„ μˆ˜ν–‰ν•œλ‹€λŠ” 말은 μž‘μ—…μ„ μˆœμ„œλŒ€λ‘œ μ²˜λ¦¬ν•œλ‹€λŠ” 말이기 λ•Œλ¬Έμ΄λ‹€. λ”°λΌμ„œ λ™κΈ° μž‘μ—…μ€ μš”μ²­ν•œ μž‘μ—…μ— λŒ€ν•΄ μˆœμ„œκ°€ μ§€μΌœμ§€λŠ” 것을 λ§ν•˜λŠ” 것이고, 비동기 μž‘μ—…μ€ μˆœμ„œκ°€ μ§€μΌœμ§€μ§€ μ•Šμ„ 수 μžˆλ‹€λŠ” 것을 λ§ν•œλ‹€.

예λ₯Όλ“€μ–΄ A, B, C λΌλŠ” 3 개의 μž‘μ—…(Task)이 μžˆλ‹€κ³  κ°€μ •ν•˜μž. 동기 λ°©μ‹μœΌλ‘œ μ‹€ν–‰ν•˜λ©΄ A → B → C μˆœμ„œλŒ€λ‘œ μ‹€ν–‰λ˜κ²Œ 되고, 비동기 λ°©μ‹μœΌλ‘œ μ‹€ν–‰ν•˜λ©΄ A → C → B λ˜λŠ” C → A → B λ“±μ˜ λ¬΄μž‘μœ„μ˜ μˆœμ„œλ‘œ μ‹€ν–‰λ˜κ²Œ λ˜λŠ” 것이닀.

Synchronous-Asynchronous
동기(Synchronous)
Synchronous-Asynchronous
비동기(Asynchronous)

μ •λ¦¬ν•˜μžλ©΄ μž‘μ—… 3개λ₯Ό μš”μ²­ν–ˆλŠ”λ° μ‘λ‹΅μ—μ„œ κ·Έ μˆœμ„œκ°€ μ§€μΌœμ§„λ‹€λ©΄ 동기이고 μ–΄λ–€ 게 λ¨Όμ € μ˜¬μ§€ λͺ¨λ₯Έλ‹€λ©΄ 비동기라고 보면 λœλ‹€.


Blocking / Non-Blocking

λΈ”λ‘œν‚Ήκ³Ό 논블둝킹은 λ‹¨μ–΄μ—μ„œ μ•Œ 수 μžˆλ“―μ΄ λ‹€λ₯Έ μš”μ²­μ˜ μž‘μ—…μ„ μ²˜λ¦¬ν•˜κΈ° μœ„ν•΄ ν˜„μž¬ μž‘μ—…μ„ block(차단, λŒ€κΈ°) ν•˜λƒ μ•ˆν•˜λƒμ˜ 유무λ₯Ό λ‚˜νƒ€λ‚΄λŠ” ν”„λ‘œμ„ΈμŠ€μ˜ μ‹€ν–‰ 방식이닀.

동기/비동기가 전체적인 μž‘μ—…μ— λŒ€ν•œ 순차적인 흐름 유무라면, λΈ”λ‘œν‚Ή/λ…ΌλΈ”λ‘œν‚Ήμ€ 전체적인 μž‘μ—…μ˜ 흐름 자체λ₯Ό 막냐 μ•ˆ λ§‰λƒλ‘œ λ³Ό 수 μžˆλŠ” 것이닀. 예λ₯Ό λ“€μ–΄, νŒŒμΌμ„ μ½λŠ” μž‘μ—…μ΄ μžˆμ„ λ•Œ, λΈ”λ‘œν‚Ή λ°©μ‹μœΌλ‘œ 읽으면 νŒŒμΌμ„ λ‹€ 읽을 λ•ŒκΉŒμ§€ λŒ€κΈ°ν•˜κ³ , λ…ΌλΈ”λ‘œν‚Ή λ°©μ‹μœΌλ‘œ 읽으면 νŒŒμΌμ„ λ‹€ 읽지 μ•Šμ•„λ„ λ‹€λ₯Έ μž‘μ—…μ„ ν•  수 μžˆλ‹€. 

Blocking-Non-Blocking

 

비동기와 λ…ΌλΈ”λ‘œν‚Ή κ°œλ… 차이

μ•„λ§ˆ μƒˆλ‚΄κΈ° κ°œλ°œμžλ“€μ΄ κ°€μž₯ ν˜Όλ™ν•˜λŠ” 뢀뢄이 비동기와 λ…ΌλΈ”λ‘œν‚Ήμ˜ 차이 뢀뢄일 것이닀. ν¬μŠ€νŒ… μ΄ˆλ°˜μ—μ„œ μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ setTimeout ν•¨μˆ˜λ₯Ό 비동기 ν•¨μˆ˜μ΄λ©° λ™μ‹œμ— λ…ΌλΈ”λ‘œν‚Ή ν•¨μˆ˜μ΄λΌκ³  ν–ˆλ‹€. μ΄λŠ” μ–΄λ– ν•œ κ΄€μ μœΌλ‘œ setTimeout 을 λ°”λΌλ³΄λŠλƒμ— 따라 각기 λΆ€λ₯΄λŠ”κ²Œ 달라지기 λ•Œλ¬Έμ΄λ‹€. 예λ₯Όλ“€μ–΄ μ•„λž˜ μ½”λ“œλŠ” setTimeout ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜μ—¬ 1초 후에 "Hello, world!"λ₯Ό 좜λ ₯ν•˜λŠ” 비동기 λ…ΌλΈ”λ‘œν‚Ή μ½”λ“œμ˜ μ˜ˆμ œμ΄λ‹€. μ½”λ“œλ₯Ό μ‹€ν–‰ν•˜λ©΄, "μ‹œμž‘"κ³Ό "끝"이 λ¨Όμ € 좜λ ₯되고, 1초 후에 "1초 후에 μ‹€ν–‰λ©λ‹ˆλ‹€!"κ°€ 좜λ ₯되게 λœλ‹€.

console.log("μ‹œμž‘");

setTimeout(() => {
  console.log("1초 후에 μ‹€ν–‰λ©λ‹ˆλ‹€!");
}, 1000);

console.log("끝");

Blocking-Non-Blocking

즉, 좜λ ₯ μˆœμ„œμ™€ μ •μ˜λœ μ½”λ“œ 라인 μˆœμ„œκ°€ λ§žμ§€ μ•Šμ€ 것이닀. μ΄λŠ” setTimeout ν•¨μˆ˜μ— λŒ€ν•΄ 타이머 μž‘μ—… μ™„λ£Œ μ—¬λΆ€λ₯Ό μ‹ κ²½ 쓰지 μ•Šκ³  λ°”λ‘œ κ·Έ λ‹€μŒ μ½˜μ†” μž‘μ—…μ„ μˆ˜ν–‰ν•˜μ˜€κΈ° λ•Œλ¬Έμ΄λ‹€. 그리고 setTimeout ν•¨μˆ˜μ˜ 타이머 μž‘μ—… μ™„λ£Œ μ•ŒλžŒμ„ 콜백 ν•¨μˆ˜λ₯Ό 톡해 값을 λ°›μ•„ 좜λ ₯ν•˜μ˜€λ‹€. λ”°λΌμ„œ setTimeout 은 비동기(Asynchronouse)이닀.

λ‹€λ₯Έ μ‹œκ°μœΌλ‘œ 보면 메인 ν•¨μˆ˜ μž‘μ—…μ— λŒ€ν•΄μ„œ setTimeout ν•¨μˆ˜λŠ” μžμ‹ μ˜ 타이머 μž‘μ—…μ„ μˆ˜ν–‰ν•˜κΈ° μœ„ν•΄ 메인 ν•¨μˆ˜λ₯Ό λΈ”λ½ν•˜μ§€ μ•Šκ³  λ°±κ·ΈλΌμš΄λ“œμ—μ„œ λ³„λ„λ‘œ μ²˜λ¦¬λ˜μ—ˆλ‹€. 메인 ν•¨μˆ˜λ₯Ό λΈ”λ½ν•˜μ§€ μ•ŠμœΌλ‹ˆ setTimeout ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜κ³  λ°”λ‘œ κ·Έ λ‹€μŒ μ½˜μ†” ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•œ 것이닀. λ”°λΌμ„œ setTimeout μ€ λ…ΌλΈ”λ‘œν‚Ή(Non-blocking)이닀.

그런데 결ꡭ은 λΉ„λ™κΈ°λ‚˜ λ…ΌλΈ”λ‘œν‚Ήμ΄λ‚˜ μΆ”κ΅¬ν•˜λŠ” 결과둜만 보자면 λ™μ‹œμ— λ‹€λ₯Έ μž‘μ—…μ„ μˆ˜ν–‰ν•œλ‹€λŠ” μ μ—μ„œ 그게 그것이라고 λ³Ό μˆ˜λ„ μžˆλ‹€. μ΄λŠ” μ‹œμ κ³Ό κ΄€λ ¨λœ 이둠적인 κ°œλ…μ΄λΌ μ‹€μ œ μ½”λ“œμ—μ„œ 경계λ₯Ό κ΅¬λΆ„ν•˜κΈ°κ°€ μ• λ§€ν•˜κΈ°λ„ ν•˜λ‹€. κ·Έλž˜μ„œ ν”„λ‘œκ·Έλž˜λ°μ—μ„  이λ₯Ό ν˜Όμš©ν•˜μ—¬ μ‚¬μš©ν•˜λŠ” 것 κ°™λ‹€. κ·ΈλŸ¬λ‚˜ μ—„μ—°ν•œ λ‚˜νƒ€λ‚΄λŠ” μ˜λ―ΈλŠ” λ‹€λ₯΄λ‹€. 😡

μš°λ¦¬κ°€ 동기/비동기, λΈ”λ‘œν‚Ή/λ…ΌλΈ”λ‘œν‚Ήμ„ ν˜Όλ™ν•˜λŠ” μ΄μœ λŠ”, μžλ°”μŠ€ν¬λ¦½νŠΈλ₯Ό 처음 배울 λ•Œ ν”„λ‘œκ·Έλž˜λ° μ„œμ μ΄λ‚˜ κ°•μ˜μ—μ„œ setTimeout κ³Ό 같은 ν•¨μˆ˜λ₯Ό '비동기 ν•¨μˆ˜' 라고 μ§€μΉ­ν•˜κ³  μ™Έμ›Œλ²„λ €μ„œ κ·Έλ ‡λ‹€κ³  μƒκ°ν•œλ‹€. κ·Έλž˜μ„œ '비동기' 라고 ν•˜λ©΄ μžμ—°μŠ€λŸ½κ²Œ 병렬 싀행을 λ– μ˜¬λΌ 비동기와 λ…ΌλΈ”λ‘œν‚Ήμ„ ν˜Όλ™ν•˜λŠ” 것이닀.
λΉ„λ™κΈ°λŠ” 좜λ ₯ μˆœμ„œμ™€ κ΄€λ ¨λœ κ°œλ…μ΄κ³  λ…ΌλΈ”λ‘œν‚Ήμ΄ 병렬 μ‹€ν–‰κ³Ό κ΄€λ ¨λœ κ°œλ…μ΄λ‹€. λ”°λΌμ„œ κΈ€μ“΄μ΄λŠ” 개인적으둜 이 뢀뢄은 잘λͺ»λ˜μ—ˆλ‹€κ³  λΉ„νŒν•˜κ³  μ‹Άλ‹€. 아무리 쑰금 λ‚œν•΄ν•œ κ°œλ…μ΄λΌλ„ μ²˜μŒλΆ€ν„° 비동기 + λ…ΌλΈ”λ‘œν‚Ή ν•¨μˆ˜λΌκ³  κ°€λ₯΄μΉ˜λŠ”것이 μΆ”ν›„λ₯Ό μœ„ν•΄ κ°œλ…μ„ λ‹€μž‘λŠ”λ° μ˜³λ‹€κ³  λ³Έλ‹€.

 

비동기 λ…ΌλΈ”λ‘œν‚Ήκ³Ό 콜백 ν•¨μˆ˜

μžλ°”μŠ€ν¬λ¦½νŠΈ 비동기 ν”„λ‘œκ·Έλž˜λ°μ—μ„œ 빠지지 μ•ŠλŠ” κ°œλ…μ΄ λ°”λ‘œ 콜백(callback) 이닀. 비동기 λ…ΌλΈ”λ‘œν‚Ήμ΄λž€ λ‹€λ₯Έ μž‘μ—…μ˜ κ²°κ³Όλ₯Ό 기닀리지 μ•Šκ³  λ³‘λ ¬μ μœΌλ‘œ μ‹€ν–‰λ˜λŠ” 방식을 λ§ν•˜λŠ”λ°, μ΄λ•Œ λ‹€λ₯Έ μž‘μ—…μ˜ μ™„λ£Œ μ—¬λΆ€λ‚˜ 결과에 λŒ€ν•œ ν›„μ²˜λ¦¬λ₯Ό μœ„ν•΄ μ΄μš©λ˜λŠ” 방식이 콜백 ν•¨μˆ˜μ΄λ‹€.

그럼 콜백 ν•¨μˆ˜λŠ” 비동기와 관련이 μžˆλŠ” κ²ƒμΌκΉŒ? λ…ΌλΈ”λ‘œν‚Ήκ³Ό 관련이 μžˆλŠ” κ²ƒμΌκΉŒ? 정닡은 λ‘˜λ‹€ 관련이 μžˆλ‹€. μ—„λ°€νžˆ λ”°μ§€μžλ©΄ 콜백 ν•¨μˆ˜λŠ” 비동기 λ…ΌλΈ”λ‘œν‚Ήμ„ κ΅¬ν˜„ν•˜λŠ” ν•˜λ‚˜μ˜ κΈ°μˆ μ΄μ§€ κ°œλ…μ΄ μ•„λ‹ˆλ‹€. 콜백 지μ˜₯(callback hell) λ•Œλ¬Έμ— 콜백 ν•¨μˆ˜ λ°©μ‹μœΌλ‘œ 비동기 λ…ΌλΈ”λ‘œν‚Ήμ„ κ΅¬ν˜„ν•˜κΈ° μ‹«λ‹€λ©΄ Promise 객체λ₯Ό μ΄μš©ν•˜μ—¬λ„ 되고 μ•„μ˜ˆ 이벀트둜 emit ν•˜μ—¬ μ²˜λ¦¬ν•˜μ—¬λ„ λœλ‹€. 방법은 μ—¬λŸ¬κ°€μ§€μ΄λ‹€. 핡심은 비동기 λ…ΌλΈ”λ‘œν‚Ήμ„ κ΅¬ν˜„ν•˜λŠ” κΈ°μˆ μ€ 콜백 외에 μ—¬λŸ¬κ°€μ§€κ°€ μžˆλ‹€λŠ” 점이고 μ½œλ°±μ€ κ·Έ 쀑 ν•˜λ‚˜μΌ λΏμ΄λΌλŠ” 것이지 동기/비동기 & λΈ”λ‘œν‚Ή/λ…ΌλΈ”λ‘œν‚Ή κ°œλ…κ³Ό 직접적인 관련은 μ—†λ‹€.

/* 콜백 ν•¨μˆ˜ λ°©μ‹μœΌλ‘œ κ΅¬ν˜„ν•œ 비동기 + λ…ΌλΈ”λ‘œν‚Ή μ„œλ²„ μš”μ²­ μž‘μ—… */

$.ajax({
  url: 'https://jsonplaceholder.typicode.com/todos/1', 
  type: 'GET', 
  dataType: 'json', 
  success: function(data) { // μš”μ²­μ΄ μ„±κ³΅ν•˜λ©΄ 호좜될 콜백 ν•¨μˆ˜
    console.log(data); 
  },
  error: function(err) { // μš”μ²­μ΄ μ‹€νŒ¨ν•˜λ©΄ 호좜될 콜백 ν•¨μˆ˜
    throw err;
  }
});

// μš”μ²­μ„ λ³΄λ‚΄λŠ” λ™μ‹œμ— λ‹€λ₯Έ μž‘μ—…μ„ μˆ˜ν–‰ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
console.log('Hello');
/* ν”„λ‘œλ―ΈμŠ€ 객체 λ°©μ‹μœΌλ‘œ κ΅¬ν˜„ν•œ 비동기 + λ…ΌλΈ”λ‘œν‚Ή μ„œλ²„ μš”μ²­ μž‘μ—… */

fetch('https://jsonplaceholder.typicode.com/todos/1') 
  .then((response) => {
    return response.json(); 
  })
  .then((data) => {
    console.log(data); 
  })
  .catch((err) => {
    throw err; 
  });

// μš”μ²­μ„ λ³΄λ‚΄λŠ” λ™μ‹œμ— λ‹€λ₯Έ μž‘μ—…μ„ μˆ˜ν–‰ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
console.log('Hello');
/* 이벀트 λ°©μ‹μœΌλ‘œ κ΅¬ν˜„ν•œ 비동기 + λ…ΌλΈ”λ‘œν‚Ή 파일 λ‹€μš΄ μž‘μ—… */

const fileReader = new FileReader(); // FileReader 객체λ₯Ό 생성
const input = document.querySelector('input');
const file = input.files[0]; // input νƒœκ·Έμ—μ„œ μ„ νƒλœ νŒŒμΌμ„ κ°€μ Έμ˜΅λ‹ˆλ‹€

fileReader.addEventListener('load', function() {
	console.log(fileReader.result); // 파일이 loadκ°€ μ™„λ£Œλ˜λ©΄ λ‚΄μš©μ„ 좜λ ₯ν•©λ‹ˆλ‹€.
});

fileReader.addEventListener('error', function(err) {
	throw err;
});

// μš”μ²­μ„ λ³΄λ‚΄λŠ” λ™μ‹œμ— λ‹€λ₯Έ μž‘μ—…μ„ μˆ˜ν–‰ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
console.log('Hello');

 

λˆ„κ°€ μ œμ–΄κΆŒμ„ 가지고 μžˆλŠλƒ

λ‹€λ₯Έ μ„œμ μ—μ„  동기/비동기와 λΈ”λ‘œν‚Ή/λ…ΌλΈ”λ‘œν‚Ήμ„ 보닀 λͺ…ν™•νžˆ κ΅¬λΆ„ν•˜κΈ° μœ„ν•΄μ„œ 'μ œμ–΄κΆŒ' μ΄λΌλŠ” μ–΄λ €μš΄ 단어λ₯Ό μ“΄λ‹€. μ œμ–΄κΆŒμ€ κ°„λ‹¨νžˆ λ§ν•΄μ„œ ν•¨μˆ˜μ˜ μ½”λ“œλ‚˜ ν”„λ‘œμ„ΈμŠ€μ˜ μ‹€ν–‰ 흐름을 μ œμ–΄ν•  수 μžˆλŠ” ꢌ리 같은 것이닀. 이 κ°œλ…μ€ 운영체제(OS)의 컀널(kernel)μ—μ„œ λ”°μ˜¨ κ°œλ…μœΌλ‘œ I/O λ™μž‘μ—μ„œ μ„€λͺ…ν•˜λŠ” 뢀뢄이닀. 즉, Blockingκ³Ό Non-Blocking은 호좜된 ν•¨μˆ˜(callee)κ°€ ν˜ΈμΆœν•œ ν•¨μˆ˜(caller)μ—κ²Œ μ œμ–΄κΆŒμ„ λ°”λ‘œ μ£ΌλŠλƒ μ•ˆμ£ΌλŠλƒλ‘œ κ΅¬λΆ„λœλ‹€. μ œμ–΄κΆŒμ΄ λ„˜μ–΄κ°€λ²„λ¦¬λ©΄ ν•΄λ‹Ή μŠ€λ ˆλ“œλŠ” λΈ”λ‘œν‚Ήλ˜κ²Œ λœλ‹€.

λ‹€μŒμ€ A ν•¨μˆ˜μ™€ B ν•¨μˆ˜ μž‘μ—…μ— λŒ€ν•΄ A ν•¨μˆ˜κ°€ B ν•¨μˆ˜λ₯Ό Blocking λ°©μ‹μœΌλ‘œ ν˜ΈμΆœν• μ‹œ μ œμ–΄κΆŒ μƒνƒœλ₯Ό λ‚˜νƒ€λ‚Έ 그림이닀.

동기-비동기-λΈ”λ‘œν‚Ή-λ…ΌλΈ”λ‘œν‚Ή
Blocking

 

  1. A ν•¨μˆ˜κ°€ B ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜λ©΄ Bμ—κ²Œ μ œμ–΄κΆŒμ΄ λ„˜μ–΄κ°„λ‹€
  2. μ œμ–΄κΆŒμ„ λ„˜κ²¨λ°›μ€ BλŠ” ν•¨μˆ˜λ₯Ό μ‹€ν–‰ν•œλ‹€.
  3. μ΄λ•Œ AλŠ” Bμ—κ²Œ μ œμ–΄κΆŒμ„ λ„˜κ²¨μ£Όμ—ˆκΈ° λ•Œλ¬Έμ— A ν•¨μˆ˜ 싀행을 μž μ‹œ λ©ˆμΆ˜λ‹€. (Block)
  4. B ν•¨μˆ˜κ°€ 싀행이 λλ‚˜λ©΄ μžμ‹ μ„ ν˜ΈμΆœν•œ Aμ—κ²Œ μ œμ–΄κΆŒμ„ λŒλ €μ€€λ‹€.
  5. μ œμ–΄κΆŒμ„ λ‹€μ‹œ 받은 A ν•¨μˆ˜λŠ” κ·Έλ‹€μŒ μž‘μ—…μ„ μ‹€ν–‰ν•œλ‹€.

λ‹€μŒμ€ A ν•¨μˆ˜μ™€ B ν•¨μˆ˜ μž‘μ—…μ— λŒ€ν•΄ A ν•¨μˆ˜κ°€ B ν•¨μˆ˜λ₯Ό Non-Blocking λ°©μ‹μœΌλ‘œ ν˜ΈμΆœν• μ‹œ μ œμ–΄κΆŒ μƒνƒœλ₯Ό λ‚˜νƒ€λ‚Έ 그림이닀.

동기-비동기-λΈ”λ‘œν‚Ή-λ…ΌλΈ”λ‘œν‚Ή
Non Blocking

  1. A ν•¨μˆ˜κ°€ B ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•œλ‹€.
  2. 호좜된 B ν•¨μˆ˜λŠ” μ‹€ν–‰λ˜μ§€λ§Œ, μ œμ–΄κΆŒμ€ A ν•¨μˆ˜κ°€ κ·ΈλŒ€λ‘œ 가지고 μžˆλŠ”λ‹€.
  3. A ν•¨μˆ˜λŠ” 계속 μ œμ–΄κΆŒμ„ 가지고 있기 λ•Œλ¬Έμ— B ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•œ 이후에도 μžμ‹ μ˜ μ½”λ“œλ₯Ό 계속 μ‹€ν–‰ν•œλ‹€.

동기/비동기 + λΈ”λ‘œν‚Ή/λ…ΌλΈ”λ‘œν‚Ή μ‘°ν•©

μ§€κΈˆκΉŒμ§€ 동기/비동기 와 λΈ”λ‘œν‚Ή/λ…ΌλΈ”λ‘œν‚Ή 각각의 차이점에 λŒ€ν•΄ μ•Œμ•„λ³΄μ•˜λ‹€. 이처럼 λ‘˜μ€ μœ μ‚¬ν•˜μ§€λ§Œ μ—„μ—°νžˆ λ‹€λ₯Έ κ°œλ…μ΄λ‹€. κ·Έλž˜μ„œ ν”„λ‘œκ·Έλž¨ μ•„ν‚€ν…μ³μ—μ„œλŠ” 이 두 κ°œλ…μ΄ ν•¨κ»˜ μ‘°ν•©λ˜μ–΄ μ‚¬μš©λœλ‹€. 예λ₯Όλ“€μ–΄ λ‹€μŒ 4κ°€μ§€λ‘œ 쑰합이 κ°€λŠ₯ν•˜λ‹€.

  1. Sync Blocking (동기 + λΈ”λ‘œν‚Ή)
  2. Async Blocking (비동기 + λΈ”λ‘œν‚Ή)
  3. Sync Non-Blocking (동기 + λ…ΌλΈ”λ‘œν‚Ή) 
  4. Async Non-Blocking (비동기 + λ…ΌλΈ”λ‘œν‚Ή)

sync-async-blocking-nonblocking

μ΄λŸ¬ν•œ 동기/비동기와 λΈ”λ‘œν‚Ή/λ…ΌλΈ”λ‘œν‚Ήμ˜ 쑰합은 ν”„λ‘œκ·Έλž¨μ΄ μž‘λ™ν•˜λŠ” 방식에 영ν–₯을 λ―ΈμΉ˜λŠ” μ€‘μš”ν•œ μš”μ†Œλ‹€. μ–΄λ– ν•œ μš”μ†Œλ₯Ό μ‘°ν•©ν•˜μ—¬ μ‚¬μš©ν•˜λŠλƒμ— 따라 ν”„λ‘œκ·Έλž¨μ˜ μ„±λŠ₯κ³Ό νš¨μœ¨μ„±μ„ 높일 수 있기 λ•Œλ¬Έμ΄λ‹€.

λŒ€ν‘œμ μΈ 예둜 Node.js λ₯Ό λ“€ 수 μžˆλ‹€. Node.jsμ—μ„œ 비동기 λ°©μ‹μœΌλ‘œ νŒŒμΌμ„ μ½κ±°λ‚˜ λ„€νŠΈμ›Œν¬ μš”μ²­μ„ 보낼 λ•ŒλŠ” 비동기 & λ…ΌλΈ”λ‘œν‚Ή 방식을 μ‚¬μš©ν•˜μ—¬ μž‘μ—…μ΄ μ™„λ£Œλ  λ•ŒκΉŒμ§€ λ‹€λ₯Έ μž‘μ—…μ„ μˆ˜ν–‰ν•  수 μžˆλ„λ‘ ν•œλ‹€. λ°˜λ©΄μ—, Node.jsμ—μ„œ μ½”λ“œ μ‹€ν–‰ μ‹œμ μ„ λŠ¦μΆ°μ£Όκ±°λ‚˜ 순차적인 μ˜μ‘΄μ„±μ΄ μžˆλŠ” μž‘μ—…μ„ μ²˜λ¦¬ν•  λ•ŒλŠ” 동기 & λΈ”λ‘œν‚Ή 방식을 μ‚¬μš©ν•˜μ—¬ μž‘μ—…μ˜ μˆœμ„œμ™€ 타이밍을 μ œμ–΄ν•  수 μžˆλ„λ‘ ν•œλ‹€.

sync-async-blocking-nonblocking
제둜초(μ‘°ν˜„μ˜)의 node.js ꡐ제

μ•„λ§ˆ μš°λ¦¬λŠ” 이미 κ°œλ…μ΄ 적용된 ν”„λ ˆμž„μ›Œν¬λ₯Ό μ΄μš©ν•΄ νŽΈλ¦¬ν•˜κ²Œ μ‚¬μš©ν•΄ μ™”μ–΄μ„œ 와닿지 μ•Šμ„ 수 μžˆλ‹€. ν•˜μ§€λ§Œ μ΄λŸ¬ν•œ 이둠적인 뢀뢄을 μ΄ν•΄ν•˜κ³  μ μš©ν•œλ‹€λ©΄ 직접 μ„€κ³„ν• λ•Œ λ”μš± 효율적인 μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜μ„ κ°œλ°œμ— 도움이 될 수 있으며, κ°œλ…λ“€μ„ λͺ…ν™•νžˆ μ•Œκ³  있으면 Node.js의 λ™μž‘ 원리와 μž₯점을 더 잘 μ΄ν•΄ν•˜κ³  ν™œμš©ν•  수 μžˆμ„ 것이닀. λ”°λΌμ„œ 동기/비동기와 λΈ”λ‘œν‚Ή/λ…ΌλΈ”λ‘œν‚Ήμ˜ κ°œλ…μ„ μ΄ν•΄ν•˜κ³  μ μ ˆν•œ 쑰합을 μ„ νƒν•˜λŠ” 것이 μ€‘μš”ν•˜λ‹€.


Sync Blocking μ‘°ν•©

Sync Blocking 쑰합은 λ‹€λ₯Έ μž‘μ—…μ΄ μ§„ν–‰λ˜λŠ” λ™μ•ˆ μžμ‹ μ˜ μž‘μ—…μ„ μ²˜λ¦¬ν•˜μ§€ μ•Šκ³  (Blocking), λ‹€λ₯Έ μž‘μ—…μ˜ μ™„λ£Œ μ—¬λΆ€λ₯Ό λ°”λ‘œ λ°›μ•„ 순차적으둜 μ²˜λ¦¬ν•˜λŠ” (Sync) 방식이닀. λ‹€λ₯Έ μž‘μ—…μ˜ κ²°κ³Όκ°€ μžμ‹ μ˜ μž‘μ—…μ— 영ν–₯을 μ£ΌλŠ” κ²½μš°μ— ν™œμš©ν•  수 μžˆλ‹€.

Sync Blocking

 

μ‹€μƒν™œ λ™μž‘ μ˜ˆμ‹œ

μ–΄λŠ κ°œλ°œνŒ€μ—μ„œ 사원1, 사원2, 사원3 와 νŒ€μž₯이 μžˆλ‹€κ³  ν•˜μž. κ°œλ°œνŒ€μž₯은 κ°œλ°œνŒ€ μž‘μ—…μ˜ 흐름을 μ‘°μœ¨ν•˜κ³ , μ‚¬μ›λ“€μ—κ²Œ 업무λ₯Ό μ§€μ‹œν•œλ‹€κ³  ν•œλ‹€.

  1. νŒ€μž₯ : 사원1씨 업무 A μ’€ ν•΄μ£Όμ„Έμš”
  2. 사원1 : λ„€ μ•Œκ² μŠ΅λ‹ˆλ‹€. (Aλ₯Ό μ²˜λ¦¬μ€‘)
  3. νŒ€μž₯ : (사원1이 Aλ₯Ό λ‹€ν• λ•ŒκΉŒμ§€ 아무일도 ν•˜μ§€ μ•Šκ³  κΈ°λ‹€λ¦°λ‹€)
  4. 사원1 : νŒ€μž₯λ‹˜ A 업무 μ™„λ£Œν–ˆμŠ΅λ‹ˆλ‹€.
  5. νŒ€μž₯ : μˆ˜κ³ ν–ˆμ–΄μš”. 사원2씨 업무 Bμ’€ ν•΄μ£Όμ„Έμš”.
  6. 사원2 : λ„€ μ•Œκ² μŠ΅λ‹ˆλ‹€. (Bλ₯Ό μ²˜λ¦¬μ€‘)
  7. νŒ€μž₯ : (사원2κ°€ Bλ₯Ό λ‹€ν• λ•ŒκΉŒμ§€ 아무일도 ν•˜μ§€ μ•Šκ³  κΈ°λ‹€λ¦°λ‹€)
  8. 사원2 : νŒ€μž₯λ‹˜ B 업무 μ™„λ£Œν–ˆμŠ΅λ‹ˆλ‹€.
  9. νŒ€μž₯ : μˆ˜κ³ ν–ˆμ–΄μš”. 사원3씨 업무 Cμ’€ ν•΄μ£Όμ„Έμš”.
  10. ...μƒλž΅

 

μ½”λ“œ λ™μž‘ μ˜ˆμ‹œ

Sync Blocking 의 λŒ€ν‘œμ μΈ 예둜 νŒŒμΌμ„ 읽어 λ‚΄μš©μ„ μ²˜λ¦¬ν•˜λŠ” λ‘œμ§μ„ λ“€ 수 μžˆλ‹€. νŒŒμΌμ„ λ¨Όμ € 읽어야 κ·Έλ‹€μŒ μž‘μ—…μ„ μ²˜λ¦¬ν•  수 있기 λ•Œλ¬Έμ΄λ‹€.

const fs = require('fs'); // 파일 μ‹œμŠ€ν…œ λͺ¨λ“ˆ 뢈러였기

// λ™κΈ°μ μœΌλ‘œ 파일 읽기
const data1 = fs.readFileSync('file1.txt', 'utf8'); // file1을 sync으둜 read 함
console.log(data1); // 파일 λ‚΄μš© 좜λ ₯ν•˜κ³  μ μ ˆν•œ 처리λ₯Ό 진행

const data2 = fs.readFileSync('file2.txt', 'utf8'); 
console.log(data2); 

const data3 = fs.readFileSync('file3.txt', 'utf8'); 
console.log(data3);

μ΄λŸ¬ν•œ Sync Blocking 은 μ½”λ“œκ°€ 순차적으둜 μ‹€ν–‰λ˜λŠ” νŠΉμ„±μ„ 가지고 μžˆλ‹€. κ·Έλž˜μ„œ Sync Blocking 쑰합은 일반적으둜 μž‘μ—…μ΄ κ°„λ‹¨ν•˜κ±°λ‚˜ μž‘μ—…λŸ‰μ΄ 적은 κ²½μš°μ— μ‚¬μš©λœλ‹€. μž‘μ€ 데이터λ₯Ό μ²˜λ¦¬ν•˜κ±°λ‚˜ 파일 ν•˜λ‚˜λ₯Ό 읽고 μ“°λŠ” κ²½μš°μ—λŠ” Sync Blocking 방식이 더 κ°„λ‹¨ν•˜κ³  직관적일 수 μžˆλ‹€. ν•˜μ§€λ§Œ μž‘μ—…λŸ‰μ΄ λ§Žκ±°λ‚˜ μ‹œκ°„μ΄ 였래 κ±Έλ¦¬λŠ” μž‘μ—…μ„ μ²˜λ¦¬ν•΄μ•Ό ν•˜λŠ” κ²½μš°μ—λŠ” Sync Blocking 방식을 μ‚¬μš©ν•˜λ©΄ 독이 λœλ‹€. μ™œλƒν•˜λ©΄ μž‘μ—…μ„ μ²˜λ¦¬ν•˜λ©΄ μž‘μ—…μ΄ 끝날 λ•ŒκΉŒμ§€ λ‹€λ₯Έ μž‘μ—…μ„ μ²˜λ¦¬ν•˜μ§€ λͺ»ν•˜λ―€λ‘œ, 전체 처리 μ‹œκ°„μ΄ 였래 걸리게 λ˜μ–΄ λΉ„νš¨μœ¨μ μ΄κ²Œ 되게 λœλ‹€. λ”°λΌμ„œ μ΄λŸ¬ν•œ κ²½μš°μ—λŠ” λ°”λ‘œ λ’€μ—μ„œ λ‹€λ£° Async Non-Blocking 방식을 μ‚¬μš©ν•˜μ—¬ μž‘μ—…μ„ μ²˜λ¦¬ν•˜λŠ” 것이 μ’‹λ‹€.

 

적용 ν”„λ‘œκ·Έλž¨ μ˜ˆμ‹œ

λŒ€ν‘œμ μœΌλ‘œ  Cλ‚˜ JAVA의 μ½”λ“œ μ‹€ν–‰ ν›„ μ»€λ§¨λ“œμ—μ„œ μž…λ ₯을 λ°›λŠ” κ²½μš°κ°€ 이에 ν•΄λ‹Ήλœλ‹€. μ‚¬μš©μžλ‘œλΆ€ν„° μž…λ ₯을 λ°›μ•„μ•Ό κ·Έ μž…λ ₯값을 가지고 λ‚΄λΆ€ 처리λ₯Ό ν•˜μ—¬ 결과값을 μ½˜μ†”μ— 좜λ ₯ν•΄μ£ΌκΈ° λ•Œλ¬Έμ— 순차적인 μž‘μ—…μ΄ μš”κ΅¬λœλ‹€. λ‚΄λΆ€μ μœΌλ‘œ λ³Έλ‹€λ©΄ μ‹€ν–‰ μ½”λ“œκ°€ μ½˜μ†”μ°½μ„ λ„μš°κ³  Please enter your name ν…μŠ€νŠΈλ₯Ό 치고 λ‚œ λ‹€μŒ μ‚¬μš©μžμ˜ 리턴값이 ν•„μš”ν•˜κΈ° λ•Œλ¬Έμ— μ œμ–΄κΆŒμ„ μ‹œμŠ€ν…œμ—μ„œ μ‚¬μš©μžλ‘œ λ„˜κ²¨ μ‚¬μš©μžκ°€ 값을 μž…λ ₯ν• λ•ŒκΉŒμ§€ κΈ°λ‹€λ¦¬λŠ” 것이닀.

동기-비동기-λΈ”λ‘œν‚Ή-λ…ΌλΈ”λ‘œν‚Ή


Async Non-Blocking μ‘°ν•©

Async Non Blocking 쑰합은 λ‹€λ₯Έ μž‘μ—…μ΄ μ§„ν–‰λ˜λŠ” λ™μ•ˆμ—λ„ μžμ‹ μ˜ μž‘μ—…μ„ μ²˜λ¦¬ν•˜κ³  (Non Blocking), λ‹€λ₯Έ μž‘μ—…μ˜ κ²°κ³Όλ₯Ό λ°”λ‘œ μ²˜λ¦¬ν•˜μ§€ μ•Šμ•„ μž‘μ—… μˆœμ„œκ°€ μ§€μΌœμ§€μ§€ μ•ŠλŠ” (Async) 방식이닀. λ‹€λ₯Έ μž‘μ—…μ˜ κ²°κ³Όκ°€ μžμ‹ μ˜ μž‘μ—…μ— 영ν–₯을 주지 μ•Šμ€ κ²½μš°μ— ν™œμš©ν•  수 μžˆλ‹€.

Async Non-Blocking

 

μ‹€μƒν™œ λ™μž‘ μ˜ˆμ‹œ

  1. νŒ€μž₯ : 사원1씨 A업무쒀 ν•΄μ£Όμ„Έμš”. (λ™μ‹œμ— μ§€μ‹œ)
  2. νŒ€μž₯ : 사원2씨 B업무쒀 ν•΄μ£Όμ„Έμš”. (λ™μ‹œμ— μ§€μ‹œ)
  3. νŒ€μž₯ : 사원3씨 C업무쒀 ν•΄μ£Όμ„Έμš”. (λ™μ‹œμ— μ§€μ‹œ)
  4. νŒ€μž₯ : λ‹€λ₯ΈμΌμ„ 해야지 ~
  5. 사원2 : νŒ€μž₯인 B λͺ¨λ‘ μ²˜λ¦¬ν–ˆμŠ΅λ‹ˆλ‹€. (μ—…λ¬΄λŸ‰μ— 따라 각 μ‚¬μ›λ§ˆλ‹€ μ™„λ£Œν•˜λŠ” μ‹œκ°„μ΄ 제각기 λ‹€λ₯Ό 수 μžˆλ‹€)
  6. 사원1 : νŒ€μž₯인 A λͺ¨λ‘ μ²˜λ¦¬ν–ˆμŠ΅λ‹ˆλ‹€.
  7. 사원3 : νŒ€μž₯인 C λͺ¨λ‘ μ²˜λ¦¬ν–ˆμŠ΅λ‹ˆλ‹€.

 

μ½”λ“œ λ™μž‘ μ˜ˆμ‹œ

μœ„μ—μ„œ 파일 읽기 μ½”λ“œλ₯Ό Sync Blocking λ°©μ‹μœΌλ‘œ κ΅¬ν˜„ν•˜μ˜€λŠ”λ° 이λ₯Ό κ·ΈλŒ€λ‘œ Async Non-Blocking λ°©μ‹μœΌλ‘œλ„ μ½”λ“œλ₯Ό κ΅¬ν˜„ν•  수 μžˆλ‹€. Sync Blocking 방식과 λ‘λ“œλŸ¬μ§„ 차이점은 호좜 ν•¨μˆ˜μ— 콜백 ν•¨μˆ˜λ₯Ό λ„£μ—ˆλ‹€λŠ” 점이닀. 이λ₯Ό 톡해 비동기 λ…ΌλΈ”λ‘œν‚Ή λ°©μ‹λŒ€λ‘œ 처리된 μž‘μ—…μ˜ κ²°κ³Όλ₯Ό ν›„μ²˜λ¦¬ ν•  수 있게 λœλ‹€. 그리고 비동기 이기 λ•Œλ¬Έμ— μž‘μ—…μ˜ μˆœμ„œλ₯Ό κ³ λ €ν•˜μ§€ μ•Šμ•„ 동기 λΈ”λ‘œν‚Ήκ³ΌλŠ” 거꾸둜 κ°€μž₯ λ¨Όμ € 'done' μ΄λΌλŠ” μ½˜μ†” λ‘œκ·Έκ°€ 찍히게 되고 κ·Έ 후에 파일 λ‚΄μš©μ΄ 좜λ ₯될 것이닀.

// λΉ„λ™κΈ°μ μœΌλ‘œ 파일 읽기
const fs = require('fs'); // 파일 μ‹œμŠ€ν…œ λͺ¨λ“ˆ 뢈러였기

fs.readFile('file.txt', 'utf8', (err, data) => { // 파일 읽기 μš”μ²­κ³Ό 콜백 ν•¨μˆ˜ 전달
  if (err) throw err; // μ—λŸ¬ 처리
  console.log(data); // 파일 λ‚΄μš© 좜λ ₯
});

fs.readFile('file2.txt', 'utf8', (err, data) => {
  if (err) throw err; 
  console.log(data);
});

fs.readFile('file3.txt', 'utf8', (err, data) => { 
  if (err) throw err; 
  console.log(data);
});

console.log('done'); // μž‘μ—… μ™„λ£Œ λ©”μ‹œμ§€ 좜λ ₯
fs.readFileSync 와 fs.readFile ν•¨μˆ˜λŠ” λ‘˜λ‹€ λ˜‘κ°™μ΄ νŒŒμΌμ„ μ½λŠ” ν•¨μˆ˜μ΄μ§€λ§Œ 동기냐 비동기냐에 따라 차이가 μžˆλ‹€.
즉, fs.readFileSync ν•¨μˆ˜λŠ” λ™κΈ°μ μœΌλ‘œ νŒŒμΌμ„ 읽고 fs.readFile ν•¨μˆ˜λŠ” λΉ„λ™κΈ°μ μœΌλ‘œ νŒŒμΌμ„ μ½λŠ”λ‹€.

이처럼 Async Non Blocking 쑰합은 μž‘μ—…λŸ‰μ΄ λ§Žκ±°λ‚˜ μ‹œκ°„μ΄ 였래 κ±Έλ¦¬λŠ” μž‘μ—…μ„ μ²˜λ¦¬ν•΄μ•Ό ν•˜λŠ” κ²½μš°μ— μ ν•©ν•˜λ‹€. 예λ₯Ό λ“€μ–΄, λŒ€μš©λŸ‰ 데이터λ₯Ό μ²˜λ¦¬ν•˜κ±°λ‚˜ λ§Žμ€ μš”μ²­μ„ μ²˜λ¦¬ν•˜λŠ” μ„œλΉ„μŠ€μ—μ„œλŠ” Async Non Blocking 방식을 μ‚¬μš©ν•˜μ—¬ ν•œ μž‘μ—…μ΄ μ²˜λ¦¬λ˜λŠ” λ™μ•ˆ λ‹€λ₯Έ μž‘μ—…μ„ μ²˜λ¦¬ν•  수 μžˆμœΌλ―€λ‘œ 전체 처리 μ‹œκ°„μ„ 쀄일 수 μžˆμ–΄ μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜ 처리 μ„±λŠ₯을 ν–₯μƒμ‹œν‚¬ 수 있게 λœλ‹€.

 

ν™œμš© μ˜ˆμ‹œ ν”„λ‘œκ·Έλž¨

비동기 λ…ΌλΈ”λ‘œν‚Ήμ„ ν™œμš©ν•˜λŠ” ν”„λ‘œκ·Έλž¨μ€ 많이 μžˆλ‹€. 그쀑 예λ₯Ό λ“€μžλ©΄, μ›Ή λΈŒλΌμš°μ €μ˜ 파일 λ‹€μš΄λ‘œλ“œκ°€ 비동기 λ…ΌλΈ”λ‘œν‚Ήμ„ ν™œμš©ν•˜λŠ” μ˜ˆμ‹œ 라고 ν•  수 μžˆλ‹€. μ›Ή λΈŒλΌμš°μ €λŠ” μ›Ή μ‚¬μ΄νŠΈμ—μ„œ νŒŒμΌμ„ λ‹€μš΄λ‘œλ“œν•  λ•Œ, 파일의 전솑이 μ™„λ£Œλ  λ•ŒκΉŒμ§€ λ‹€λ₯Έ μž‘μ—…μ„ ν•˜μ§€ μ•Šκ³  κΈ°λ‹€λ¦¬λŠ” 것이 μ•„λ‹ˆλΌ, λ‹€λ₯Έ νƒ­μ΄λ‚˜ 창을 μ—΄κ±°λ‚˜ μ›Ή μ„œν•‘μ„ ν•  수 μžˆλ‹€. μ΄λŠ” μ›Ή λΈŒλΌμš°μ €κ°€ 파일 λ‹€μš΄λ‘œλ“œλ₯Ό λΉ„λ™κΈ°μ μœΌλ‘œ μ²˜λ¦¬ν•˜κ³ , 콜백 ν•¨μˆ˜λ₯Ό 톡해 λ‹€μš΄λ‘œλ“œκ°€ μ™„λ£Œλ˜λ©΄ μ•Œλ €μ£ΌλŠ” λ°©μ‹μœΌλ‘œ κ΅¬ν˜„λ˜μ–΄ 있기 λ•Œλ¬Έμ΄λ‹€.

Async Non-Blocking
νŒŒμΌλ“€μ΄ 거의 λ™μ‹œμ— λ‹€μš΄ λ°›μŒμ„ Waterfall κ·Έλž˜ν”„μ—μ„œ μ‹œκ°μ μœΌλ‘œ 확인할 수 μžˆλ‹€


Sync Non-Blocking μ‘°ν•©

Sync Non-Blocking 쑰합은 λ‹€λ₯Έ μž‘μ—…μ΄ μ§„ν–‰λ˜λŠ” λ™μ•ˆμ—λ„ μžμ‹ μ˜ μž‘μ—…μ„ μ²˜λ¦¬ν•˜κ³  (Non Blocking), λ‹€λ₯Έ μž‘μ—…μ˜ κ²°κ³Όλ₯Ό λ°”λ‘œ μ²˜λ¦¬ν•˜μ—¬ μž‘μ—…μ„ μˆœμ°¨λŒ€λ‘œ μˆ˜ν–‰ ν•˜λŠ” (Sync) 방식이닀.

Sync Non-Blocking

 

μ‹€μƒν™œ λ™μž‘ μ˜ˆμ‹œ

νŒ€μž₯이 업무 A, B, Cλ₯Ό 사원 1, 2, 3 μ—κ²Œ μ‹œν‚€λ €κ³  ν•œλ‹€. 그런데 업무 νŠΉμ„±μƒ 업무 Aλ₯Ό μ™„λ£Œν•΄μ•Ό 업무 Bλ₯Ό ν•  수 있고, 업무 Bλ₯Ό μ™„λ£Œν•΄μ•Ό 업무 Cλ₯Ό ν•  수 μžˆλ‹€κ³  ν•œλ‹€.

  1. νŒ€μž₯ : 사원1씨 업무 A μ’€ ν•΄μ£Όμ„Έμš”
  2. 사원1 : λ„€ μ•Œκ² μŠ΅λ‹ˆλ‹€. (Aλ₯Ό μ²˜λ¦¬μ€‘)
  3. νŒ€μž₯ : λ‹€μŒ 업무 Bλ₯Ό ν•˜λ €λ©΄ Aκ°€ μ™„λ£Œλ˜μ•Ό ν•˜λŠ”λ°.. 사원1씨 λ‹€ν–ˆμ–΄μš”?
  4. 사원1 : μ•„μ§μ΄μš” A μ²˜λ¦¬μ€‘μž…λ‹ˆλ‹€
  5. νŒ€μž₯ : 사원1씨 λ‹€ν–ˆμ–΄μš”?
  6. 사원1 : μ•„μ§μ΄μš” A μ²˜λ¦¬μ€‘μž…λ‹ˆλ‹€
  7. 사원1 : νŒ€μž₯λ‹˜ A λͺ¨λ‘ μ™„λ£Œν–ˆμŠ΅λ‹ˆλ‹€
  8. νŒ€μž₯ : μˆ˜κ³ ν–ˆμ–΄μš”. 사원2씨 업무 Bμ’€ ν•΄μ£Όμ„Έμš”.
  9. 사원2 : λ„€ μ•Œκ² μŠ΅λ‹ˆλ‹€. (Bλ₯Ό μ²˜λ¦¬μ€‘)
  10. νŒ€μž₯ : λ‹€μŒ 업무 Cλ₯Ό ν•˜λ €λ©΄ Bκ°€ μ™„λ£Œλ˜μ•Ό ν•˜λŠ”λ°.. 사원2씨 λ‹€ν–ˆμ–΄μš”?
  11. ...μƒλž΅

 

μ½”λ“œ λ™μž‘ μ˜ˆμ‹œ

동기 + λ…ΌλΈ”λ‘œν‚Ή μ½”λ“œλ₯Ό ν‘œν˜„ν•˜λŠ”λ° μ ν•©ν•œ λŒ€μ€‘μ μΈ μ–Έμ–΄λ‘œ μžλ°”(Java)λ₯Ό λ“€ μˆ˜μžˆλ‹€. μŠ€λ ˆλ“œ(Thread) 객체λ₯Ό λ§Œλ“€μ–΄ μš”μ²­ μž‘μ—…μ„ λ°±κ·ΈλΌμš΄λ“œμ— 돌게 ν•˜κ³  메인 λ©”μ„œλ“œμ—μ„œ while문을 톡해 μŠ€λ ˆλ“œκ°€ λͺ¨λ‘ μ²˜λ¦¬λ˜μ—ˆλŠ”μ§€ λŠμž„μ—†μ΄ ν™•μΈν•˜κ³ , μ²˜λ¦¬κ°€ μ™„λ£Œλ˜λ©΄ λ‹€μŒ 메인 μž‘μ—…μ„ μˆ˜ν–‰ν•œλ‹€.

// Runnable μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•˜λŠ” 클래슀 μ •μ˜
class MyTask implements Runnable {
    @Override
    public void run() {
        // λΉ„λ™κΈ°λ‘œ μ‹€ν–‰ν•  μž‘μ—…
        System.out.println("Hello from a thread!");
    }
}

public class Main {
    public static void main(String[] args) {
        // Thread 객체 생성
        Thread thread = new Thread(new MyTask());

        // μŠ€λ ˆλ“œ μ‹€ν–‰
        thread.start();

        // Non-Blockingμ΄λ―€λ‘œ λ‹€λ₯Έ μž‘μ—… 계속 κ°€λŠ₯
        System.out.println("Main thread is running...");

        // Syncλ₯Ό μœ„ν•΄ μŠ€λ ˆλ“œμ˜ μž‘μ—… μ™„λ£Œ μ—¬λΆ€ 확인
        while (thread.isAlive()) {
            System.out.println("Waiting for the thread to finish...");
        }
        System.out.println("Thread finished!");
        
        System.out.println("Run the next tasks");
    }
}

Sync Non-Blocking

λΆ„λͺ… μŠ€λ ˆλ“œλ₯Ό μ΄μš©ν•˜μ—¬ μž‘μ—…μ„ λ³‘λ ¬μ μœΌλ‘œ μ²˜λ¦¬ν•˜λ„λ‘ μ§€μ‹œν–ˆμ§€λ§Œ, 메인 μ½”λ“œμ˜ while문을 μˆ˜ν–‰ν•¨μœΌλ‘œμ„œ μš”μ²­ν•œ μž‘μ—…μ˜ μ™„λ£Œ μ—¬λΆ€λ₯Ό 계속 ν™•μΈν•˜κ³  결과적으둜 κ²°κ΅­ λ™κΈ°μ μœΌλ‘œ μž‘μ—…μ„ μˆœμ„œλŒ€λ‘œ μˆ˜ν–‰λ¨μ„ λ³Ό 수 μžˆλ‹€. 

Sync Non-Blocking

μžλ°”μŠ€ν¬λ¦½νŠΈ(Javascript) κ²½μš°μ—λŠ” 동기 + λ…ΌλΈ”λ‘œν‚Ή μ½”λ“œλ₯Ό κ΅¬ν˜„ν•˜κΈ°μ—λŠ” μ§€μ›ν•˜λŠ” λ©”μ„œλ“œμ— ν•œκ³„κ°€ μžˆμ–΄ μ™„λ²½νžˆ ν‘œν˜„ν•  μˆ˜λŠ” μ—†λ‹€. λ‹€λ§Œ 이와 λΉ„μŠ·ν•˜κ²Œ ν‘œν˜„ν•  수 μžˆλŠ” 기법이 μžˆλŠ” 데 λ°”λ‘œ async/await ν‚€μ›Œλ“œ 이닀. 기본적으둜 Promise.then ν•Έλ“€λŸ¬ 방식은 비동기 λ…ΌλΈ”λ‘œν‚Ή 방식이라 λ³Ό 수 μžˆλ‹€. μ΄λ•Œ 비동기 μž‘μ—…λ“€ κ°„μ˜ μˆœμ„œκ°€ μ€‘μš”ν•˜λ‹€λ©΄ await ν‚€μ›Œλ“œλ₯Ό 톡해 λ™κΈ°μ μœΌλ‘œ μ²˜λ¦¬ν•΄ 쀄 수 μžˆλ‹€.

예λ₯Ό λ“€μ–΄ Node.jsμ—μ„œ μ—¬λŸ¬κ°œμ˜ νŒŒμΌμ„ μ½μ–΄μ„œ λ‚΄μš©μ„ λΉ„κ΅ν•˜λŠ” μž‘μ—…μ„ ν•œλ‹€κ³  κ°€μ •ν•΄λ³΄μž. 이λ₯Ό Sync Non-Blocking λ°©μ‹μœΌλ‘œ μž‘μ„±ν•œλ‹€λ©΄, μ„Έ νŒŒμΌμ„ λ™μ‹œμ— 읽기 μ‹œμž‘ν•˜κ³  (Non Blocking), 두 파일의 읽기가 λͺ¨λ‘ μ™„λ£Œλ˜λ©΄ λ‚΄μš©μ„ λΉ„κ΅ν•˜λŠ” ν›„μ²˜λ¦¬λ₯Ό μ§„ν–‰ν•œλ‹€ (Sync).

const fs = require('fs'); 
const { promisify } = require('util'); // μœ ν‹Έλ¦¬ν‹° λͺ¨λ“ˆ 뢈러였기
const readFileAsync = promisify(fs.readFile); // fs.readFile ν•¨μˆ˜λ₯Ό Promise 객체λ₯Ό λ°˜ν™˜ν•˜λŠ” ν•¨μˆ˜λ‘œ λ³€ν™˜

async function readFiles() {
  try {
    // Promise.all() λ©”μ†Œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ μ—¬λŸ¬ 개의 비동기 μž‘μ—…μ„ λ³‘λ ¬λ‘œ μ²˜λ¦¬ν•©λ‹ˆλ‹€. (비동기 λ…ΌλΈ”λ‘œν‚Ή)
    const [data1, data2, data3] = await Promise.all([
      readFileAsync('file.txt', 'utf8'), // file.txt νŒŒμΌμ„ μ½μŠ΅λ‹ˆλ‹€.
      readFileAsync('file2.txt', 'utf8'), // file2.txt νŒŒμΌμ„ μ½μŠ΅λ‹ˆλ‹€.
      readFileAsync('file3.txt', 'utf8') // file3.txt νŒŒμΌμ„ μ½μŠ΅λ‹ˆλ‹€.
    ]);

    // 파일 읽기가 μ™„λ£Œλ˜λ©΄ data에 파일 λ‚΄μš©μ΄ λ“€μ–΄μ˜΅λ‹ˆλ‹€.
    console.log(data1); // file.txt 파일 λ‚΄μš©μ„ 좜λ ₯ν•©λ‹ˆλ‹€.
    console.log(data2); // file2.txt 파일 λ‚΄μš©μ„ 좜λ ₯ν•©λ‹ˆλ‹€.
    console.log(data3); // file3.txt 파일 λ‚΄μš©μ„ 좜λ ₯ν•©λ‹ˆλ‹€.

    // 파일 비ꡐ 둜직 μ‹€ν–‰...

  } catch (err) {
    throw err;
  }
}

readFiles(); // async ν•¨μˆ˜λ₯Ό 호좜
async/await은 비동기 λ…ΌλΈ”λ‘œν‚Ή 방식을 동기 λ…ΌλΈ”λ‘œν‚Ή λ°©μ‹μœΌλ‘œ λ°”κΏ”μ£ΌλŠ” 기법이라고 ν•  수 μžˆμ§€λ§Œ, κ·ΈλŸ¬λ‚˜ async/await은 λ‚΄λΆ€μ μœΌλ‘œλŠ” μ—¬μ „νžˆ 비동기 λ…ΌλΈ”λ‘œν‚Ή λ°©μ‹μœΌλ‘œ λ™μž‘ν•œλ‹€λŠ” 점은 μœ μ˜ν•˜μž. async ν•¨μˆ˜ μžμ²΄κ°€ 메인 콜 μŠ€νƒ(call stack)이 λͺ¨λ‘ μ‹€ν–‰λ˜μ–΄ λΉ„μ›Œμ Έμ•Ό μˆ˜ν–‰ν•˜κΈ° λ•Œλ¬Έμ— 비동기 λ…ΌλΈ”λ‘œν‚Ήμ΄κΈ° λ•Œλ¬Έμ΄λ‹€. 

 

ν™œμš© μ˜ˆμ‹œ ν”„λ‘œκ·Έλž¨

동기 λ…ΌλΈ”λ‘œν‚Ήμ€ ν”ν•˜μ§€ μ•ŠλŠ” μΌ€μ΄μŠ€μ΄μ§€λ§Œ κ·Έλž˜λ„ 이λ₯Ό ν‘œν˜„ν•  수 μžˆλŠ” ν”„λ‘œκ·Έλž¨μ΄ μžˆλ‹€. κ²Œμž„μ—μ„œ 맡을 μ΄λ™ν• λ•Œλ₯Ό μƒκ°ν•΄λ³΄μž. μš°μ„  맡 데이터λ₯Ό λͺ¨λ‘ λ‹€μš΄λ‘œλ“œ ν•΄μ•Ό ν•  것이닀. κ·Έλ™μ•ˆ ν™”λ©΄μ—λŠ” λ‘œλ”© 슀크린이 λœ¬λ‹€. 이 λ‘œλ”© μŠ€ν¬λ¦°μ€ λ‘œλ”©λ°”κ°€ μ±„μ›Œμ§€λŠ” ν”„λ‘œκ·Έλž¨μ΄ μˆ˜ν–‰ν•˜κ³  μžˆλŠ” 것이닀. 즉, μ œμ–΄κΆŒμ€ μ—¬μ „νžˆ λ‚˜ν•œν…Œ μžˆμ–΄ 화면에 λ‘œλ“œμœ¨μ΄ ν‘œμ‹œλ˜λŠ” 것이닀. 그리고 λŠμž„μ—†μ΄ 맡 데이터가 μ–΄λŠμ •λ„ λ‘œλ“œκ°€ λ¬λŠ”μ§€ λŠμž„μ—†μ΄ μ‘°νšŒν•œλ‹€. μžμ‹ μ˜ μž‘μ—…μ„ κ³„μ†ν•˜κ³  μžˆμ§€λ§Œ λ‹€λ₯Έ μž‘μ—…κ³Όμ˜ 동기λ₯Ό μœ„ν•΄ κ³„μ†ν•΄μ„œ λ‹€λ₯Έ μž‘μ—…μ΄ λλ‚¬λŠ”μ§€ μ‘°νšŒν•˜λŠ” 것이닀.

동기-비동기-λΈ”λ‘œν‚Ή-λ…ΌλΈ”λ‘œν‚Ή

 

Sync Blocking vs Sync Non-Blocking

그런데 κ°€λ§Œνžˆ 보면 λΈ”λ‘œν‚Ήμ΄λ“  λ…ΌλΈ”λ‘œν‚Ήμ΄λ“  메인 ν•¨μˆ˜μ—μ„œ 결ꡭ은 μ½”λ“œλ₯Ό 순차적으둜 μˆ˜ν–‰ν•˜κΈ° λ•Œλ¬Έμ— 전체 μž‘μ—…μ˜ μ΅œμ’… κ±Έλ¦° μ‹œκ°„μ€ λ‘˜μ΄ 차이가 μ—†μ–΄ 보인닀. 그럼 두 방식은 λ„κΈ΄κ°œκΈ΄μΈ 것인가?

μ„±λŠ₯ μ°¨μ΄λŠ” 상황에 따라 λ‹€λ₯΄κ² μ§€λ§Œ, 일반적으둜 동기 + λ…ΌλΈ”λ‘œν‚Ήμ΄ 동기 + λΈ”λ‘œν‚Ήλ³΄λ‹€ 효율적일 수 μžˆλ‹€. μ™œλƒν•˜λ©΄ 동기 + λ…ΌλΈ”λ‘œν‚Ήμ€ ν˜ΈμΆœν•˜λŠ” ν•¨μˆ˜κ°€ μ œμ–΄κΆŒμ„ 가지고 μžˆμ–΄μ„œ λ‹€λ₯Έ μž‘μ—…μ„ λ³‘λ ¬μ μœΌλ‘œ μˆ˜ν–‰ν•  수 있기 λ•Œλ¬Έμ΄λ‹€. λ°˜λ©΄μ— 동기 + λΈ”λ‘œν‚Ήμ€ ν˜ΈμΆœν•˜λŠ” ν•¨μˆ˜κ°€ μ œμ–΄κΆŒμ„ μžƒμ–΄μ„œ λ‹€λ₯Έ μž‘μ—…μ„ μˆ˜ν–‰ν•  수 μ—†κΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€

κ²Œμž„ λ‘œλ”© ν™”λ©΄κ³Ό λ”λΆˆμ–΄ 동기 + λ…ΌλΈ”λ‘œν‚Ήμ˜ λ˜λ‹€λ₯Έ μ˜ˆμ œλ‘œλŠ” λΈŒλΌμš°μ €μ—μ„œ νŒŒμΌμ„ λ‹€μš΄λ‘œλ“œν•˜λ©΄ λ‚˜νƒ€λ‚˜λŠ” λ‹€μš΄λ‘œλ“œ 진행바λ₯Ό λ“€ 수 κ°€ μžˆλ‹€.

Sync Non-Blocking

μ›ΉλΈŒλΌμš°μ €μ—μ„œ νŒŒμΌμ„ λ‹€μš΄λ‘œλ“œ ν•  경우 μž‘μ—…μ€ μ›ΉλΈŒλΌμš°μ €μ˜ Web APIs 으둜 μž‘μ—…μ„ λ°±κ·ΈλΌμš΄λ“œλ‘œ λ„˜κΈ°κ³  'μ œμ–΄κΆŒ'을 λ°”λ‘œ λ°˜ν™˜λ°›μ•„ λ‹€λ₯Έ μž‘μ—…μ„ μˆ˜ν–‰ν•  수 μžˆλ‹€. 이것이 Non Blocking 이닀.

그런데 μ›ΉλΈŒλΌμš°μ €λŠ” 파일 λ‹€μš΄λ‘œλ“œ μž‘μ—…μ˜ μ™„λ£Œ 여뢀에 관심이 μžˆλ‹€. 즉, λ‹€μš΄λ‘œλ“œ μž‘μ—…μ΄ μ–Έμ œ λλ‚˜κ³  μ–Όλ§ˆλ‚˜ μ§„ν–‰λ˜μ—ˆλŠ”μ§€ 파일 λ‹€μš΄λ‘œλ“œ λ‘œλ“œμœ¨μ„ λΈŒλΌμš°μ € ν•˜λ‹¨λ°”μ— ν‘œμ‹œν•΄μ€€λ‹€. 그리고 파일이 λͺ¨λ‘ λ‹€μš΄λ‘œλ“œ μ™„λ£Œλ˜λ©΄ μ‚¬μš©μžκ°€ μ›ν•˜λŠ” μ΅œμ’… μž‘μ—…μΈ 파일 λ‹€μš΄λ‘œλ“œ μž‘μ—…μ„ μˆ˜ν–‰ν•˜κ²Œ λœλ‹€. 이것이 Synchronous 이닀.

μ΄λ•Œ μš°λ¦¬λŠ” νŒŒμΌμ„ λ‹€μš΄λ‘œλ“œ ν•˜λ©΄μ„œ μ›Ήμ„œν•‘μ„ ν•˜κ±°λ‚˜ 유튜브 μŒμ•…μ„ 듀을 수 μžˆλ‹€. μ œμ–΄κΆŒμ„ 가지고 있기 λ•Œλ¬Έμ— λΈŒλΌμš°μ €κ°€ λ©€ν‹° νƒœμŠ€ν‚Ήμ„ ν•˜λ„λ‘ 적절히 μ½”λ“œλ₯Ό κ΅¬ν˜„ν•˜μ˜€κΈ° λ•Œλ¬Έμ— κ°€λŠ₯ν•œ 것이닀. λ”°λΌμ„œ 동기 + λ…ΌλΈ”λ‘œν‚Ή 방식은 일반적인 동기 + λΈ”λ‘œν‚Ή 방식보닀 κ΅¬ν˜„μ— 따라 더 효율적으둜 μž‘μ—…μ„ 처리 ν•  수 μžˆλ‹€κ³  λ³Ό 수 μžˆλ‹€. (μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ async/await 으둜 μƒμƒν•˜λ©΄ 였히렀 이해가 μ•ˆλ μˆ˜κ°€ μžˆλ‹€. μžλ°”μ˜ μŠ€λ ˆλ“œ 객체둜 μƒμƒν•˜μž)


Async Blocking μ‘°ν•©

Async Blocking 쑰합은 λ‹€λ₯Έ μž‘μ—…μ΄ μ§„ν–‰λ˜λŠ” λ™μ•ˆ μžμ‹ μ˜ μž‘μ—…μ„ λ©ˆμΆ”κ³  κΈ°λ‹€λ¦¬λŠ” (Blocking), λ‹€λ₯Έ μž‘μ—…μ˜ κ²°κ³Όλ₯Ό λ°”λ‘œ μ²˜λ¦¬ν•˜μ§€ μ•Šμ•„ μˆœμ„œλŒ€λ‘œ μž‘μ—…μ„ μˆ˜ν–‰ν•˜μ§€ μ•ŠλŠ” (Async) 방식이닀. Async-blocking 의 κ²½μš°λŠ” μ‹€λ¬΄μ—μ„œ 잘 λ§ˆμ£Όν•˜κΈ° 쉽지 μ•Šμ•„ 닀룰일이 거의 μ—†λ‹€. κ·Έλž˜μ„œ κ·Έλƒ₯ λ„˜μ–΄κ°€λ„ 크게 λ¬Έμ œλŠ” μ—†λ‹€.

Async Blocking

 

Async Blocking vs Sync Blocking

μœ„ μ‚¬μ§„λ§Œ 보더라도 μœ„μ˜ Sync-blocking μˆ˜ν–‰ κ·Έλ¦Όκ³Ό 큰 차이가 μ—†μ–΄ 보인닀. μ‹€μ œλ‘œ λ…μžλΆ„μ΄ λŠλ‚€ κ·ΈλŒ€λ‘œ κ°œλ…μ μœΌλ‘œ 차이가 μžˆμ„ 뿐이지 μ •λ§λ‘œ μ„±λŠ₯적으둜 차이가 μ—†λ‹€.

보톡 Async-blocking은 κ°œλ°œμžκ°€ 비동기 λ…ΌλΈ”λ‘ν‚ΉμœΌλ‘œ 처리 ν•˜λ €λ‹€κ°€ μ‹€μˆ˜ν•˜λŠ” κ²½μš°μ— λ°œμƒν•˜κ±°λ‚˜, μžκΈ°λ„ λͺ¨λ₯΄κ²Œ λΈ”λ‘œν‚Ή μž‘μ—…μ„ μ‹€ν–‰ν•˜λŠ” μ˜λ„μΉ˜ μ•Šμ€ κ²½μš°μ— μ‚¬μš©λœλ‹€. κ·Έλž˜μ„œ 이 방식을 μ•ˆν‹° νŒ¨ν„΄(anti-pattern)이라고 μΉ˜λΆ€ν•˜κΈ°λ„ ν•œλ‹€.

 

ν™œμš© μ˜ˆμ‹œ ν”„λ‘œκ·Έλž¨

λ‹€λ§Œ Async Blocking 이 μ‹€μ œλ‘œ 적용된 싀무 사둀가 있긴 ν•˜λ‹€. Node.js + MySQL의 쑰합이 λŒ€ν‘œμ μΈλ°, Node.jsμ—μ„œ 비동기 λ°©μ‹μœΌλ‘œ λ°μ΄ν„°λ² μ΄μŠ€μ— μ ‘κ·Όν•˜κΈ° λ•Œλ¬Έμ— Async μ΄μ§€λ§Œ, MySQL λ°μ΄ν„°λ² μ΄μŠ€μ— μ ‘κ·Όν•˜κΈ° μœ„ν•œ MySQL λ“œλΌμ΄λ²„κ°€ λΈ”λ‘œν‚Ή λ°©μ‹μœΌλ‘œ μž‘λ™λ˜κΈ° λ•Œλ¬Έμ΄λ‹€.

Async Blocking

  1. JavaScriptλŠ” 비동기 λ°©μ‹μœΌλ‘œ MySQL에 쿼리λ₯Ό 보낸닀. (Async)
  2. MySQL은 쿼리λ₯Ό μ²˜λ¦¬ν•˜λ©΄μ„œ JavaScriptμ—κ²Œ μ œμ–΄κΆŒμ„ λ„˜κ²¨μ£Όμ§€ μ•ŠλŠ”λ‹€. (Blocking)
  3. 그러면 JavaScriptλŠ” λ‹€λ₯Έ μž‘μ—…μ„ 계속 μˆ˜ν–‰ν•  수 μžˆμ§€λ§Œ, MySQL의 결과값을 ν•„μš”λ‘œ ν•˜κΈ° λ•Œλ¬Έμ— MySQL이 쿼리λ₯Ό μ™„λ£Œν•  λ•ŒκΉŒμ§€ κΈ°λ‹€λ €μ•Ό λœλ‹€.
  4. κ²°κ΅­ Sync Blockingκ³Ό μž‘μ—… μˆ˜ν–‰μ— 차이가 μ—†κ²Œ λœλ‹€.

μ΄λ ‡κ²Œ JavaScript와 MySQL의 쑰합은 λΉ„λ™κΈ°μ μ΄λ©΄μ„œλ„ λΈ”λ‘œν‚Ήλ˜λŠ” Async Blocking 쑰합이라고 ν•  수 μžˆλ‹€. μ΄λŸ¬ν•œ μ˜€λ¬˜ν•œ 쑰합은 였히렀 κ°œλ°œμžμ—κ²Œ ν˜Όλ™λ§Œ μΌμœΌν‚€κΈ° λ•Œλ¬Έμ— κ·Έλž˜μ„œ μ‹€λ¬΄μ—μ„œλŠ” Node.js μ„œλ²„ ν”„λ‘œκ·Έλž˜λ°ν• λ•Œ μ•„μ˜ˆ async/await둜 동기 처리λ₯Ό ν•˜λŠ” νŽΈμ΄λ‹€.

const mysql = require('mysql');

// connectDB ν•¨μˆ˜λ₯Ό μ •μ˜
async function connectDB () {
  // DB μ—°κ²° 정보λ₯Ό 담은 객체 생성
  let connectionInfo = {
    host: 'localhost', // DB 호슀트 μ£Όμ†Œ
    user: 'root', // DB μœ μ € 이름
    password: '1234', // DB λΉ„λ°€λ²ˆν˜Έ
    database: 'spyncdb' // DB 이름
  };
  
  // connection 객체λ₯Ό μƒμ„±ν•˜κ³  λ°˜ν™˜
  let connection = mysql.createConnection(connectionInfo);
  return connection;
}

// mysql 라이브러리λ₯Ό μ‚¬μš©ν•˜λŠ” 경우
async function userHandler (username, displayName, profilePicture, email) {
  // DB에 μ—°κ²°
  connection = await connectDB() 
  
  // DBλ₯Ό 선택
  await connection.query ('USE spyncdb;'); 
  
  // 쿼리λ₯Ό μ‹€ν–‰ν•˜κ³  κ²°κ³Όλ₯Ό λ°›μŒ
  let result = await connection.query ('SELECT * FROM users WHERE username = ?', [username]); 
}

// userHandler ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜κ³  user_id 값을 μ–»μœΌλ €κ³  함
let user_id = await userHandler (aUser.username, aUser.displayName, aUser.profilePicture, aUser.email); // userHandler ν•¨μˆ˜κ°€ 비동기 μž‘μ—…μ„ μ™„λ£Œν•  λ•ŒκΉŒμ§€ κΈ°λ‹€λ¦Ό
console.log (user_id); // user_id 좜λ ₯

# 참고자료

https://medium.com/from-the-scratch/wtf-is-synchronous-and-asynchronous-1a75afd039df

https://notes.arkalim.org/notes/programming/asynchronous%20programming/

https://www.youtube.com/watch?v=oEIoqGd-Sns

https://joooing.tistory.com/entry/%EB%8F%99%EA%B8%B0%EB%B9%84%EB%8F%99%EA%B8%B0-%EB%B8%94%EB%A1%9C%ED%82%B9%EB%85%BC%EB%B8%94%EB%A1%9C%ED%82%B9

https://velog.io/@ellyheetov/Asynchoronous-VS-Synchoronous-1

https://velog.io/@nittre/%EB%B8%94%EB%A1%9C%ED%82%B9-Vs.-%EB%85%BC%EB%B8%94%EB%A1%9C%ED%82%B9-%EB%8F%99%EA%B8%B0-Vs.-%EB%B9%84%EB%8F%99%EA%B8%B0

https://ttl-blog.tistory.com/782