본문 바로가기

dev-log

I/O와 리소스 스트림에 대한 단상

Input/Output은 컴퓨터와 바깥 세상 간의 상호작용이다. 프로그램의 입장에서 Input은 바깥 세상으로부터 받은 전기신호, 또는 데이터이다. 프로그램의 입장에서 Output은 바깥 세상으로 보낸 전기신호, 또는 데이터이다.

 

Input과 Output은 각각과 관련된 동작을 설명하기도 한다.

입력은 데이터가 어디에서부터 램으로 이동하는 것, 또는 이동하는 흐름.

출력은 컴퓨터가 입력을 받아 결과를 내는 것, 또는 결과를 내는 흐름 으로 쓰인다.

디스크, 다른 서버, 다른 디바이스 =  대상

      입력             출력
대상 --------> 컴퓨터 -------> 대상

내가 어떤 대상으로부터 데이터를 읽는다 = 입력
내가 어떤 대상으로 데이터를 보낸다 = 출력

리소스란

프로그램의 세계로부터 그 너머의 세계에 데이터를 전송하는 일과 너머의 세계의 데이터들을 프로그램의 세계에서 읽는 일을 중개하는 건 운영체제다. 운영체제는 데이터와 프로그램 사이를 중개하기 위해 네트워크 소켓, 파일과 같은 자료구조를 만들었다. 이 자료구조들은 리소스(자원)라는 큰 범주 안에 있다. 리소스는 운영체제가 하드웨어 리소스를 제어하는 동작을 추상화한 코드다.

 

운영체제는 리소스를 핸들이라는 값으로 매핑했다. 매핑을 한 목적은 간단하다. 모든 프로그램들이 리소스 구현체의 메소드를 호출하지 않고 “읽고” “쓴다” 는 명령어만으로 실제로 입력 데이터를 받고 출력 데이터를 전송하게 하기 위함이다. 핸들은 다양한 구현체들을 리소스라는 공통된 방식으로 접근/조작할 수 있게 추상화한 것이다.

 

프로그램이 리소스를 사용하기 위해선 먼저 리소스에 대한 접근 권한을 요청해야 한다. 운영체제에 이를 요청하면 운영체제는 프로세스와 핸들 간 매핑작업을 실행하고 핸들에 대한 값을 리턴한다. 이 경우를 리소스를 열었다고 표현한다. 그리고 프로그램이 리소스에 대한 값을 할당한 경우 리소스를 가지고 있다고 표현한다. 프로그램이 리소스를 가지고 있으면 이를 가지고 운영체제의 시스템 콜을 통해 데이터를 읽거나 쓸 수 있는 것이다. 무언가 일을 마치고 프로세스는 운영체제에 핸들 값을 반환하고 리소스와의 연결을 종료하겠다는 요청을 보낸다. 운영체제는 핸들을 제거하고 실제 구현체가 차지한 자원들을 해제한다. 이를 리소스를 닫았다고 표현한다.

 

어떤 리소스를 사용할지는 핸들을 요청하는 시스템 콜을 통해 정의된다. 디스크 파일의 경우 open(), fopen() , 네트워크 소켓은 socket() 과 같은 것이 있다. 여기서 받은 리턴값은 핸들이고, 이 핸들을 가지고 다시 Input 하겠다, Output 하겠다는 시스템콜 을 보내는 방식인 것이다.

 

 

리소스를 통해 I/O를 할 때에는

시스템 콜을 통해 데이터를 읽거나 쓸 때, 운영체제는 한 번에 모든 데이터를 처리하지 않는다. 운영체제는 보통 데이터의 일부분(chunk)을 버퍼(buffer)에 담아 필요한 만큼 프로그램에 전달하거나 프로그램이 요청한 크기만큼 데이터를 전송한다. 프로그램은 데이터를 전부 읽거나 전송할 때까지 연속적으로 시스템 콜을 호출한다.

 

리소스를 닫지 않는다면..

운영체제는 열린 리소스에 대해 “아 이 프로그램이 이 리소스를 사용하는 구나” 라는 상태를 계속 가지고 있다. 즉 점유 상태로 유지하고 있는 것이다. 근데 어떤 프로세스는 사용할 수 있는 파일 디스크립터의 수가 정해져 있다. 사용하지도 않는 리소스 때문에 사용할 수 있는 파이가 차지되는 현상을 리소스 누수라고 한다. 즉, 리소스 누수를 막기 위해서는 리소스를 항상 닫아야 한다.

 

스트림

스트림이라는 자료구조는 리소스 요청과 해제, 시스템 콜 호출과 같은 많은 동작을 묶어놨으며, 핸들을 상태로 가지고 있다. 프로그램과 스트림 그리고 운영체제는 다음과 같은 의존성을 띈다.

프로그램 --------------> 스트림 <------------------ 운영체제

 

스트림은 핸들과 핸들을 이용한 동작(읽기, 쓰기), 그리고 핸들 자체에 대한 동작을 하나로 묶어놓은 것이다.

 

왜 이름이 스트림인 것일까? 그 이유는 데이터를 버퍼 단위로 전달하는 특성 때문이다. 쪼개서 받은 데이터를 프로그램 어딘가에 할당하고, 프로그램 어딘가에 할당한 데이터는 쪼개어져서 핸들에 전달한다.

 

전체 데이터는 쪼개어져서 물이 흐르듯이 이동한다. 근원지가 프로그램이냐 리소스냐일 뿐..

스트림은 흐르는 데이터를 중개하는 공간이다. 그래서 스트림인 것이다…

'dev-log' 카테고리의 다른 글

[Granola] 001  (0) 2025.01.03
[Javascript] Promise.all  (1) 2024.12.09
[JavaScript] 자바스크립트의 배열  (0) 2024.12.03
URL과 프론트엔드 상태에 관한 짧은 생각  (2) 2024.11.30
렌더링 렌더링 그놈의 렌더링  (0) 2023.08.14