티스토리 뷰
I/O란?
블로킹(Blocking)/논블로킹(Non-Blocking)은 입출력(I/O)에 관한 문제입니다. 이때 I/O는 뭘까요? I/O는 파일 읽기⋅쓰기, 데이터 베이스 읽기⋅쓰기, 네트워킹 보내기⋅결과 받기 등을 의미합니다. 즉, 이 I/O들은 CPU와 메모리의 밖과 소통하는 작업들입니다. 이 작업들의 특징은 대부분 처리가 느리다는건데요, 이 점을 생각하시고 다음 개념들에 대해 읽어주시면 되겠습니다.
블로킹(Blocking)/논블로킹(Non-Blocking)
블로킹/논블로킹은 이 오래걸리는 I/O 작업을 스레드가 기다릴 것이냐 아니냐 입니다. 스레드가 기다리는 방식을 블로킹 이라고 하고, 기다리지 않는 방식을 논블로킹이라고 합니다.
블로킹
어떤 스레드가 작업을 처리하다가 I/O가 발생했다고 해봅시다. 예를 들면 사용자가 파일을 저장하는 이벤트를 발생시켜서 내용을 디스크(HDD, SSD)에 저장해야하는 작업입니다.
I/O 작업은 주로 백그라운드에서 일어납니다. (항상은 아닙니다.) 대게 I/O 작업은 system call을 통해 운영체제에 요청되며 이 요청을 처리하기 위해 새로운 스레드를 생성하거나, 스레드 풀에서 기존에 생성된 스레드에 I/O 작업을 할당해 진행됩니다. 그래서 개발자가 직접 관리할 수 있는 어플리케이션의 스레드 풀을 application layer라고 하고 시스템 단의 스레드 풀을 system layer 라고 표현하였으니 참고해주세요.
블로킹은 스레드가 I/O 작업을 기다리는 방식입니다. 따라서 기다리는 동안 Thread는 아무것도 하지 못하고 기다리는 상태가 됩니다. 그리고 I/O가 완료되었다는 메세지를 받아야 다시 동작할 수 있습니다.
논블로킹
논블로킹 방식은 I/O를 시작하자마자 바로 함수를 리턴합니다. 완료(성공/실패) 여부는 알 수 없고 I/O 작업이 성공적으로 시작했는지(pending 상태) 정도만 알려주는 것이죠. 하지만 이 덕분에 Thread는 마냥 기다리지 않고 다른 작업을 할 수 있게 되었습니다.
동기(Synchronous)/비동기(Asynchronous)
동기와 비동기는 I/O 처리 완료 후의 작업, 즉 callback을 어떤 스레드에서 처리하는지의 문제입니다. 정확히는 호출 스레드에서 처리하는가, 다른 스레드에서 처리하는가의 차이입니다.
동기
동기는 콜백을 I/O 작업을 호출한 스레드에서 실행합니다. 블로킹 방식일 때는 이해하기 쉽습니다. 'I/O를 기다렸다가 완료됐다고 응답을 받으면 콜백을 실행한다' 입니다.
비동기
비동기 방식에선 꼭 호출 스레드가 콜백을 실행하지 않아도 됩니다. 논블로킹 작업을 할 때 Thread1이 I/O 요청 후에 받은 작업(Task2)이 너무 길어져서 당장 콜백을 처리할 수 없는 상황이라면 여유있는 스레드(Thread2)가 콜백을 실행하게 됩니다.
여기까지 봤을 때 블로킹-동기, 논블로킹-비동기가 같은 것 아니냐고 생각되실 수 있습니다. 하지만 논블로킹/블로킹과 동기/비동기는 다른 개념이므로 두 개념을 크로스해서 사용할 수도 있습니다.
논블로킹 - 동기
논블로킹-동기 방식입니다. 논블로킹이므로 Thread1은 I/O가 끝나는 것을 기다리지 않습니다. 하지만, 동기 방식이기 때문에 I/O를 시작한 스레드가 callback을 실행해야하므로 Task2가 길어진다면 callback은 큐에서 대기해야합니다. 처리가 느려지겠죠. 또한 Thread2는 작업이 가능함에도 불구하고 놀고 있게 됩니다.
운이 좋아서 Task2가 I/O 완료보다 빨리 끝나면 바로 callback을 실행하므로 블로킹-동기 방식과 동일하게 동작하면서 기다리는 동안에 Task2도 처리해 효율이 극대화 될 수도 있겠습니다만, Task2가 언제끝날지 보장할 수 없으므로 이는 잘 쓰이지 않습니다.
블로킹 - 비동기
블로킹-비동기는 호출 스레드가 I/O 완료를 기다리는데, 콜백은 다른 곳에서 실행할 수도 있는 방식입니다. I/O가 끝나자마자 반응할 수는 있지만 I/O가 진행되는동안 스레드가 두개나 놀고 있어 비효율적입니다.
따라서 논블로킹-동기, 블로킹-비동기는 잘 사용되지 않는다고 보시면 됩니다.
멀티 스레드(Multi-threaded)와 동시성(Concurrency) 그리고 싱글스레드(Single-threaded)
멀티 스레드와 싱글 스레드는 말 그대로 여러개의 스레드를 운용하는 것과 단일 스레드를 운용하는 것의 차이입니다. 개념은 비슷하지만 CPU단의 프로세스와 스레드 얘기는 조금 접어두고 언어 단에 초점을 맞춰서 얘기를 해보겠습니다. 예를 들어서 Java는 JVM을 통해 멀티 스레딩를 지원하고, Javascript 엔진은 싱글 스레드입니다.
순차성
말 그대로 하나의 스레드에서 Task가 순차적으로 처리되는 것을 말합니다. 싱글스레드에만 적용되는 개념은 아니고, 멀티스레드에서도 각 스레드가 순차적으로 작업을 수행하고 있다면 순차성입니다.
동시성
동시성은 여러 스레드에서 Task가 동시에 실행될 수 있는 것을 뜻합니다. 즉, 멀티스레드 환경에서 구현될 수 있습니다.
공유 자원 문제
그런데 동시성은 '공유 자원'에 대한 문제가 있습니다. 같은 데이터(공유 자원)에 여러 스레드가 접근할 때, 타이밍이나 접근 순서에 따라 결과가 달라지는 문제입니다. 경쟁 상태, race condition이라고도 합니다.
이렇게 동시에 처리되는 일정이 각각 공유 자원에 접근하게 된다면 각 스레드의 결과 값이 일치하지 않는 문제가 발생할 수 있습니다.
예를 들어 Thread1이 공유 자원을 변경하고 있는 도중에 Thread2가 읽기 작업을 진행한다면 최종적으로 알고 있는 공유자원의 마지막 상태값이 각각 달라질 수 있습니다.
그런데 운좋게 위 작업(Thread2)이 늦게 할당되어서 정상적인 결과가 나올 수도 있습니다. 이 코드는 결론적으로 어떤 상황에서는 정상 동작을 하고 어떤 상황에서는 비정상 동작하게 됩니다.
이런 임계영역에 대한 공유 자원문제는 lock, 뮤텍스, 세마포어 등으로 해결할 수 있습니다. 한번에 하나의 스레드만 공유자원에 접근하게 하는 방식입니다. 뮤텍스나 세마포어는 CPU에서 제공하는 원자적인 기능을 사용해야합니다. 따라서 어플리케이션 개발자가 직접적으로 뮤텍스나 세마포어를 개발하여 쓸 일은 드물고, actor와 같이 스레드 접근 제한을 지원하는 객체를 사용하거나 이뮤터블 객체를 이용해 thread-safe하게 개발합니다.
싱글 스레드 논블로킹
자바스크립트는 싱글스레드라고 들어보셨죠? 어떻게 js는 논블로킹-비동기 처리를 할 수 있을까요?
바로 기다림이 필요한 작업은 Web API에 위임해 처리하기 때문입니다. 브라우저단에서 실행되는 WebAPI가 완료를 알리면 callback이 queue에 쌓이게 되고, 이벤트루프가 하나뿐인 thread의 상황을 보고 적절히 callback을 배치해 처리하게 하는 것이죠. 즉 js 엔진 자체는 싱글스레드이지만, 브라우저의 멀티 스레드(workder thread)를 이용하고 있다고 생각할 수 있습니다.
읽어주셔서 감사합니다.
Ref.
널널한 개발자님의 Bloking/Non-Bloking I/O 강의
그리고 ChatGPT...
'기타' 카테고리의 다른 글
클라이언트 MVC에 대해서 + MV* 아키텍처 (0) | 2023.04.24 |
---|---|
코드 커버리지(Code Coverage)란? (0) | 2022.12.10 |
자주 쓰이는 주요 HTTP Status code 정리 (0) | 2022.12.06 |
클라이언트의 리액티브 프로그래밍(Reactive programming) - 데이터 바인딩과 Rx (0) | 2022.12.03 |
[SOMA] 소프트웨어마에스트로 13기 수료 후기 (2) | 2022.12.01 |
- Total
- Today
- Yesterday
- ios
- MVC
- 비동기/동기
- 리액티브 프로그래밍
- SWM
- healthkit
- reactive programming
- MVI
- Architecture Pattern
- TestCode
- programmers
- DocC
- Swift Concurrency
- 노션
- SwiftUI
- Flux
- swift
- GetX
- MVVM
- 프로그래머스
- design pattern
- notion
- Bloking/Non-bloking
- 소프트웨어마에스트로
- coordinator pattern
- 코디네이터 패턴
- RX
- 아키텍쳐 패턴
- Flutter
- combine
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |