본문 바로가기
카테고리 없음

큐(Queue)를 활용한 스케줄링 기법 (버퍼, 프로세스)

by kguidebook0001 2026. 2. 1.


컴퓨터 시스템과 네트워크 서버는 제한된 자원(CPU, 메모리, 대역폭)을 효율적으로 관리해야 하는 숙명을 안고 있습니다. 수많은 요청이 동시에 쏟아질 때, 시스템이 마비되지 않고 안정적으로 서비스를 제공할 수 있는 비결은 바로 큐(Queue) 자료구조를 활용한 스케줄링(Scheduling)버퍼링(Buffering) 기술에 있습니다. 이 글에서는 큐가 운영체제의 프로세스 관리와 데이터 통신에서 어떻게 '완충 지대' 역할을 수행하는지, 그리고 대표적인 스케줄링 알고리즘인 FCFS와 라운드 로빈(Round Robin)이 큐를 통해 어떻게 구현되는지 심층 분석합니다.

1. 시스템 안정성의 핵심: 버퍼(Buffer)로서의 큐

하드웨어 장치 간, 혹은 소프트웨어 모듈 간에는 필연적으로 속도 차이가 존재합니다. 예를 들어, CPU는 초고속으로 데이터를 처리하지만, 디스크나 네트워크 I/O는 상대적으로 매우 느립니다. 이 속도 불균형을 해소하기 위해 큐를 버퍼(Buffer)로 사용합니다.

1-1. 생산자-소비자 패턴 (Producer-Consumer Pattern)

큐 기반 스케줄링의 가장 기본이 되는 모델입니다.

  • 생산자(Producer): 데이터를 생성하여 큐(버퍼)에 넣는(Enqueue) 주체입니다.
  • 소비자(Consumer): 큐에서 데이터를 꺼내어(Dequeue) 처리하는 주체입니다.

이 구조 덕분에 생산자는 소비자의 처리 속도를 기다릴 필요 없이 데이터를 큐에 쌓아두고 자신의 작업을 계속할 수 있으며, 이를 비동기 처리(Asynchronous Processing)라고 합니다.

2. 운영체제(OS)의 프로세스 스케줄링 기법

운영체제는 CPU라는 핵심 자원을 여러 프로세스(프로그램)가 공평하게 사용할 수 있도록 관리해야 합니다. 이때 준비 큐(Ready Queue)를 사용하여 실행 대기 중인 프로세스들을 줄 세웁니다.

2-1. 선입선출 스케줄링 (FCFS / FIFO)

가장 단순한 형태의 스케줄링으로, 큐의 본질인 FIFO(First-In, First-Out)를 그대로 따릅니다. 먼저 도착한 프로세스가 CPU를 먼저 할당받습니다.

  • 장점: 구현이 매우 간단하고 공평해 보입니다.
  • 단점(Convoy Effect): 처리 시간이 긴 프로세스가 앞에 있으면, 뒤에 있는 짧은 작업들이 하염없이 기다려야 하는 병목 현상이 발생합니다.

2-2. 라운드 로빈 (Round Robin)

시분할 시스템(Time Sharing System)에서 사용되는 방식으로, 큐의 순서를 따르되 시간 할당량(Time Quantum)을 둡니다.

  • 동작 원리: 프로세스가 할당된 시간 동안만 CPU를 사용하고, 작업이 끝나지 않으면 다시 준비 큐의 맨 뒤로 들어갑니다.
  • 특징: 큐가 원형으로 연결된 것처럼 동작하며, 모든 프로세스가 응답 시간을 보장받을 수 있어 멀티태스킹 환경에 적합합니다.

3. 파이썬(Python)을 이용한 작업 스케줄링 구현

파이썬의 `queue` 모듈은 스레드 간 통신을 위한 안전한(Thread-safe) 큐를 제공합니다. 다음은 큐를 이용해 작업을 순차적으로 처리하는 간단한 워커(Worker) 스케줄링 예제입니다.


import queue
import time
import threading

# 작업 대기열 (버퍼 역할)
task_queue = queue.Queue()

def worker(worker_id):
    while True:
        # 큐에서 작업 가져오기 (비어있으면 대기)
        task = task_queue.get()
        if task is None:
            break
            
        print(f"[Worker {worker_id}] Processing task: {task}")
        time.sleep(1)  # 작업 처리 시뮬레이션
        task_queue.task_done()

# 1. 스레드(소비자) 생성 및 실행
threads = []
for i in range(2):
    t = threading.Thread(target=worker, args=(i,))
    t.start()
    threads.append(t)

# 2. 작업(생산자) 투입
for item in ["Email", "Rendering", "Data Backup", "Log Analysis"]:
    task_queue.put(item)

# 3. 모든 작업 완료 대기
task_queue.join()

# 4. 작업 종료 신호 전송
for i in range(2):
    task_queue.put(None)

위 코드에서 `task_queue`는 작업 요청이 폭주하더라도 워커 스레드가 처리할 수 있는 속도에 맞춰 작업을 분배하는 버퍼 역할을 수행합니다.

[핵심 요약 : 큐와 스케줄링]
1. 버퍼링: 큐는 빠른 CPU와 느린 I/O 장치 사이의 속도 차이를 완충하여 시스템의 비동기 처리를 가능하게 합니다.
2. 스케줄링: 운영체제는 준비 큐(Ready Queue)를 통해 FCFS나 라운드 로빈 방식으로 프로세스의 CPU 점유 순서를 제어합니다.
3. 안정성: 트래픽 폭주 시 요청을 큐에 쌓아둠으로써(대기열), 서버가 다운되지 않고 순차적으로 처리할 수 있는 탄력성을 제공합니다.