동시성 vs. 병렬성 – 정의와 차이점

동시성과 병렬 처리의 차이점을 파악하고, 소프트웨어 개발 요구사항에 가장 적합한 방식을 알아보세요.
2 분 읽기
Concurrency vs Parallelism blog image

이 블로그에서는 동시성과 병렬 처리에 대해 자세히 논의하여 애플리케이션에 가장 적합한 개념을 선택하는 데 도움을 드릴 것입니다.

동시성(Concurrency)이란 무엇인가?

간단히 말해, 동시성은 소프트웨어 개발에서 여러 작업을 동시에 처리하기 위해 사용되는 개념입니다. 그러나 이론적으로 모든 작업을 정확히 동시에 실행하는 것은 아닙니다. 대신 시스템이나 애플리케이션이 여러 작업 사이를 빠르게 전환함으로써 동시에 다중 작업을 관리할 수 있게 하여 병렬 처리의 환상을 만들어냅니다. 이 과정은 작업 인터리빙(task interleaving)으로도 알려져 있습니다.

예를 들어, 여러 사용자 요청을 처리해야 하는 웹 서버를 생각해 보십시오.

  • 사용자 1이 데이터를 가져오기 위해 서버에 요청을 보냅니다.
  • 사용자 2가 서버에 파일을 업로드하라는 요청을 보냅니다.
  • 사용자 3이 이미지를 가져오기 위해 서버에 요청을 보냅니다.

동시성이 없다면, 각 사용자는 이전 요청이 완료될 때까지 기다려야 합니다.

  • 1단계: CPU가 스레드 1에서 데이터 검색 요청 처리를 시작합니다.
  • 2단계: 스레드 1이 결과를 기다리는 동안 CPU는 스레드 2에서 파일 업로드 프로세스를 시작합니다.
  • 3단계: 스레드 2가 파일 업로드 완료를 기다리는 동안, CPU는 스레드 3에서 이미지 검색을 시작합니다.
  • 4단계: 그런 다음 CPU는 리소스 가용성에 따라 이 3개의 스레드 사이를 전환하여 3가지 작업을 동시에 완료합니다.
Example of 3 tasks running concurrently

동기식 실행 방식에 비해 동시 실행 방식은 훨씬 빠르며, 단일 코어 환경에서 시스템의 응답 시간, 자원 활용도 및 처리량을 향상시키는 데 매우 유용합니다. 그러나 동시 실행은 단일 코어에 국한되지 않으며, 멀티 코어 환경에서도 구현될 수 있습니다.

동시성의 사용 사례

  • 반응형 사용자 인터페이스.
  • 웹 서버.
  • 실시간 시스템.
  • 네트워킹 및 I/O 작업.
  • 백그라운드 처리.

다양한 동시성 모델

현대 애플리케이션의 복잡성과 요구 사항이 증가함에 따라 개발자들은 기존 접근 방식의 단점을 해결하기 위해 새로운 동시성 모델을 도입했습니다. 주요 동시성 모델과 그 용도는 다음과 같습니다:

1. 협력적 멀티태스킹

이 모델에서는 작업이 적절한 시점에 자발적으로 스케줄러에 제어권을 넘겨주어 다른 작업을 처리할 수 있게 합니다. 이러한 양보는 작업이 유휴 상태이거나 I/O 작업을 기다릴 때 주로 발생합니다. 컨텍스트 전환이 애플리케이션 코드 내에서 관리되므로 구현하기 가장 쉬운 모델 중 하나입니다.

예시:

  • 경량 임베디드 시스템
  • 초기 버전의 Microsoft Windows (Windows 3.x)
  • 클래식 맥 OS

실제 적용 사례:

2. 선점형 다중 작업

운영 체제 또는 런타임 스케줄러가 스케줄링 알고리즘에 따라 작업들을 강제로 중지시키고 다른 작업들에 CPU 시간을 할당합니다. 이 모델은 모든 작업이 동등한 CPU 시간을 확보하도록 보장합니다. 그러나 더 복잡한 컨텍스트 전환이 필요합니다.

예시:

실제 적용 사례:

  • 현대 운영 체제(Windows, macOS, Linux)
  • 웹 서버.

3. 이벤트 기반 동시성

이 모델에서는 작업이 작은 비차단 작업으로 분할되어 큐에 대기열 처리됩니다. 그런 다음 작업은 큐에서 작업을 가져와 필요한 작업을 수행한 후 다음 작업으로 이동하여 시스템의 상호작용성을 유지합니다.

예시:

  • Node.js (JavaScript 런타임).
  • JavaScript의 async/await 패턴.
  • Python의 asyncio 라이브러리.

실제 적용 사례:

  • Node.js와 같은 웹 서버.
  • 실시간 채팅 애플리케이션.

4. 액터 모델

비동기적으로 메시지를 송수신하기 위해 액터를 사용합니다. 각 액터는 한 번에 하나의 메시지만 처리하므로 공유 상태를 피하고 잠금 장치의 필요성을 줄입니다.

예시:

실제 적용 분야:

5. 반응형 프로그래밍

이 모델을 사용하면 데이터 스트림(관측 가능 객체)을 생성하고, 이를 처리하는 방법(연산자)과 반응하는 방법(관찰자)을 정의할 수 있습니다. 데이터 변경이나 이벤트가 발생하면 스트림을 통해 자동으로 모든 구독 관찰자에게 전파됩니다. 이 접근 방식은 비동기 데이터와 이벤트 관리를 용이하게 하며, 복잡한 데이터 흐름을 처리하는 깔끔하고 선언적인 방법을 제공합니다.

예시:

실제 적용 사례:

  • 실시간 데이터 처리 파이프라인.
  • 대화형 사용자 인터페이스.
  • 동적이며 반응형 데이터 처리가 필요한 애플리케이션.

병렬 처리란 무엇인가?

병렬 처리는 소프트웨어 개발에서 여러 작업을 동시에 처리하기 위해 널리 사용되는 개념입니다. 작업 간 빠른 전환을 통해 병렬 처리의 환상을 만드는 동시성과 달리, 병렬 처리는 실제로 여러 CPU 코어나 프로세서를 사용하여 여러 작업을 동시에 실행합니다. 이는 더 큰 작업을 병렬로 실행할 수 있는 더 작고 독립적인 하위 작업으로 분할하는 것을 포함합니다. 이 과정을 작업 분해라고 합니다.

예를 들어, 분석 및 시뮬레이션 실행 후 보고서를 생성하는 데이터 처리 애플리케이션을 생각해 보십시오. 병렬 처리가 없다면 이는 하나의 큰 작업으로 실행되어 완료하는 데 상당한 시간이 소요됩니다. 그러나 병렬 처리를 선택하면 작업 분해를 통해 작업을 훨씬 빠르게 완료할 수 있습니다.

병렬 처리는 다음과 같이 작동합니다:

  • 1단계: 주요 작업을 독립적인 하위 작업으로 분할합니다. 이 하위 작업들은 다른 작업의 입력을 기다리지 않고 실행될 수 있어야 합니다. 다만, 의존성이 존재할 경우 올바른 순서로 실행되도록 스케줄링해야 합니다. 본 예시에서는 하위 작업 간 의존성이 없다고 가정하겠습니다.
  • 하위 작업 1: 데이터 분석 수행.
  • 하위 작업 2: 보고서 생성.
  • 하위 작업 3: 시뮬레이션 실행.
  • 단계 2: 3개의 하위 작업을 3개의 코어에 할당합니다.
  • 단계 3: 마지막으로 각 하위 작업의 결과를 결합하여 원래 작업의 최종 출력을 얻습니다.
Example of 3 tasks running in parallel

병렬 처리의 사용 사례

  • 과학적 계산 및 시뮬레이션.
  • 데이터 처리.
  • 이미지 처리.
  • 기계 학습.
  • 위험 분석.

다양한 병렬 처리 모델

동시성과 마찬가지로, 병렬 처리도 멀티코어 프로세서와 분산 컴퓨팅 자원을 효율적으로 활용하기 위한 여러 모델을 가지고 있습니다. 주요 병렬 처리 모델과 그 용도는 다음과 같습니다:

1. 데이터 병렬 처리

이 모델은 데이터를 여러 프로세서에 분배하고 각 데이터 하위 집합에 대해 동일한 작업을 동시에 수행합니다. 독립적인 하위 작업으로 쉽게 분할할 수 있는 작업에 특히 효과적입니다.

예시:

  • SIMD (단일 명령어, 다중 데이터) 연산.
  • 병렬 배열 처리.
  • MapReduce 프레임워크.

실제 적용 분야:

  • 이미지 및 신호 처리
  • 대규모 데이터 분석
  • 과학적 시뮬레이션

2. 작업 병렬화

작업 병렬성은 전체 작업을 서로 다른 프로세서에서 동시에 실행할 수 있는 더 작고 독립적인 작업들로 나누는 것을 포함합니다. 각 작업은 서로 다른 연산을 수행합니다.

예시:

  • Java의 스레드 기반 병렬 처리.
  • .NET의 병렬 작업.
  • POSIX 스레드.

실제 적용 사례:

  • 여러 클라이언트 요청을 처리하는 웹 서버.
  • 병렬 알고리즘 구현.
  • 실시간 처리 시스템.

3. 파이프라인 병렬 처리

파이프라인 병렬 처리에서는 작업이 단계로 나뉘며, 각 단계가 병렬로 처리됩니다. 데이터는 파이프라인을 통해 흐르며, 각 단계는 동시에 작동합니다.

예시:

  • 유닉스 파이프라인 명령어.
  • 이미지 처리 파이프라인.
  • ETL(추출, 변환, 로드) 도구의 데이터 처리 파이프라인.

실제 적용 사례:

  • 비디오 및 오디오 처리.
  • 실시간 데이터 스트리밍 애플리케이션.
  • 제조 및 조립 라인 자동화.

4. 포크/조인 모델

이 모델은 작업을 더 작은 하위 작업으로 분할(포크)하고, 이를 병렬로 실행한 후 결과를 결합(조인)하는 방식을 포함합니다. 분할 정복 알고리즘에 유용합니다.

예시:

  • 자바의 포크/조인 프레임워크.
  • 병렬 재귀 알고리즘(예: 병렬 병합 정렬).
  • 인텔 스레딩 빌딩 블록스(TBB).

실제 적용 사례:

  • 대규모 데이터셋 정렬과 같은 복잡한 계산 작업.
  • 재귀 알고리즘.
  • 대규모 과학적 계산.

5. GPU 병렬 처리

GPU 병렬 처리는 그래픽 처리 장치(GPU)의 대규모 병렬 처리 능력을 활용하여 수천 개의 스레드를 동시에 실행하므로 고도로 병렬화된 작업에 이상적입니다.

예시:

  • NVIDIA의CUDA (Compute Unified Device Architecture).
  • OpenCL (Open Computing Language).
  • 딥 러닝을 위한TensorFlow.

실제 적용 분야:

  • 머신 러닝 및 딥 러닝.
  • 실시간 그래픽 렌더링.
  • 고성능 과학 컴퓨팅.

동시성 대 병렬성

동시성과 병렬 처리의 작동 방식을 충분히 이해하셨으니, 이제 여러 측면에서 비교하여 양쪽의 장점을 최대한 활용하는 방법을 살펴보겠습니다.

1. 자원 활용도

  • 동시성: 단일 코어 내에서 여러 작업을 실행하며, 작업 간에 자원을 공유합니다. 예를 들어, CPU는 유휴 상태나 대기 기간 동안 작업 간에 전환합니다.
  • 병렬 처리: 여러 코어나 프로세서를 사용하여 작업을 동시에 실행합니다.

2. 초점

  • 동시성: 동시에 여러 작업을 관리하는 데 중점을 둡니다.
  • 병렬 처리: 동시에 여러 작업을 실행하는 데 중점을 둡니다.

3. 작업 실행

  • 동시성: 작업이 교차 실행되는 방식. CPU의 빠른 컨텍스트 전환이 병렬 실행의 착시를 만들어 냅니다.
  • 병렬성: 서로 다른 프로세서나 코어에서 진정한 병렬 방식으로 작업이 실행됩니다.

4. 컨텍스트 전환

  • 동시성: CPU가 작업 간 전환을 통해 동시 실행의 모습을 연출할 때 빈번한 컨텍스트 전환이 발생합니다. 작업이 자주 유휴 상태가 되면 성능에 부정적인 영향을 미칠 수 있습니다.
  • 병렬성: 작업이 별도의 코어나 프로세서에서 실행되므로 컨텍스트 전환이 최소화되거나 발생하지 않습니다.

5. 사용 사례

  • 동시성: 디스크 I/O, 네트워크 통신 또는 사용자 입력과 같은 I/O에 의존하는 작업.
  • 병렬 처리: 수학적 계산, 데이터 분석, 이미지 처리 등 집중적인 처리가 필요한 CPU 바운드 작업.
A table explaining and comparing the differences between concurrency and parallelism

동시성과 병렬 처리를 함께 사용할 수 있을까?

위의 비교를 바탕으로, 동시성과 병렬 처리는 많은 상황에서 서로를 보완한다는 점을 알 수 있습니다. 그러나 실제 사례를 살펴보기 전에, 멀티코어 환경에서 이 조합이 내부적으로 어떻게 작동하는지 살펴보겠습니다. 이를 위해 데이터 읽기, 쓰기 및 분석을 수행하는 웹 서버를 고려해 보겠습니다.

1단계: 작업 식별

먼저 애플리케이션 내 I/O에 의존하는 작업과 CPU에 의존하는 작업을 식별해야 합니다. 이 경우:

  • I/O 바운드 – 데이터 읽기 및 쓰기.
  • CPU 바운드 – 데이터 분석.

2단계: 동시성 실행

데이터 읽기 및 쓰기 작업은 I/O 바인딩 작업이므로 단일 코어 내에서 별도의 스레드로 실행할 수 있습니다. 서버는 이벤트 루프를 사용하여 이러한 작업을 관리하고 스레드 간에 빠르게 전환하며 작업 실행을 교차 실행합니다. Python asyncio와 같은 비동기 프로그래밍 라이브러리를 사용하여 이러한 동시성 동작을 구현할 수 있습니다.

단계 3: 병렬 실행

CPU 바인딩 작업은 여러 코어에 할당되어 병렬로 처리될 수 있습니다. 이 경우 데이터 분석을 여러 하위 작업으로 분할하여 각 하위 작업을 독립적인 코어에서 실행합니다. Python concurrent.futures와 같은 병렬 실행 프레임워크를 사용하여 이 동작을 구현할 수 있습니다.

단계 4: 동기화와 조정

서로 다른 코어에서 실행되는 스레드 간에 상호 의존성이 발생할 수 있습니다. 이러한 상황에서는 데이터 무결성을 보장하고 경합 조건을 방지하기 위해 잠금(lock)이나 세마포어(semaphore) 같은 동기화 메커니즘이 필요합니다.

Visualization of concurrency and parallelism in multi-core processing

아래 코드 조각은 Python을 사용하여 동일한 애플리케이션에서 동시성과 병렬 처리를 활용하는 방법을 보여줍니다:

import asyncio
from concurrent.futures import ProcessPoolExecutor
import os

# I/O 바운드 작업 시뮬레이션 (데이터 읽기)
async def read_data():
    await asyncio.sleep(1)  # I/O 지연 시뮬레이션
    data = [1, 2, 3, 4, 5]  # 더미 데이터
    print("데이터 읽기 완료")
    return data

# I/O 바운드 작업 시뮬레이션 (데이터 쓰기)
async def write_data(data):
    await asyncio.sleep(1)  # I/O 지연 시뮬레이션
    print(f"데이터 쓰기 완료: {data}")

# CPU 바운드 작업 시뮬레이션 (데이터 분석)
def analyze_data(data):
    print(f"CPU에서 데이터 분석 시작: {os.getpid()}")
    result = [x ** 2 for x in data]  # 계산 시뮬레이션
    print(f"CPU에서 데이터 분석 완료: {os.getpid()}")
    return result

async def handle_request():
    # 동시성: 비동기적으로 데이터 읽기
    data = await read_data()
    
    # 병렬 처리: 데이터를 병렬로 분석
    loop = asyncio.get_event_loop()
    with ProcessPoolExecutor() as executor:
        analyzed_data = await loop.run_in_executor(executor, analyze_data, data)
    
    # 동시성: 데이터를 비동기적으로 쓰기
    await write_data(analyzed_data)

async def main():
    # 여러 요청 처리 시뮬레이션
    await asyncio.gather(handle_request(), handle_request())

# 서버 실행
asyncio.run(main())

동시성과 병렬 처리 결합의 실제 사례

이제 동시성과 병렬 처리를 결합하여 최적의 성능을 달성할 수 있는 일반적인 사용 사례를 살펴보겠습니다.

1. 금융 데이터 처리

금융 데이터 처리 시스템의 주요 작업에는 일상적인 운영을 지원하면서 데이터 수집, 처리 및 분석이 포함됩니다.

  • 동시성은 비동기 I/O 작업을 사용하여 주식 시장과 같은 다양한 리소스에서 금융 데이터를 가져오는 데 사용됩니다.
  • 수집된 데이터를 분석하여 보고서를 생성합니다. 이는 CPU 집약적인 작업으로, 병렬 처리를 활용하여 일상 운영에 영향을 주지 않고 병렬로 실행합니다.

2. 영상 처리

비디오 처리 시스템의 주요 작업에는 비디오 파일 업로드, 인코딩/디코딩 및 분석이 포함됩니다.

  • 비동기 I/O 작업을 사용하여 동시성을 활용하면 여러 동영상 업로드 요청을 처리할 수 있습니다. 이를 통해 사용자는 다른 업로드가 완료될 때까지 기다리지 않고 동영상을 업로드할 수 있습니다.
  • 동시성은 인코딩, 디코딩, 동영상 파일 분석과 같은 CPU 집약적 작업에 사용됩니다.

3. 데이터 스크래핑

데이터 스크래핑 서비스의 주요 작업에는 다양한 웹사이트에서 데이터를 가져오고 수집된 데이터를 파싱/분석하여 인사이트를 도출하는 것이 포함됩니다.

  • 데이터 수집은 동시성을 사용하여 처리할 수 있습니다. 이는 데이터 수집이 효율적으로 이루어지도록 보장하며 응답을 기다리는 동안 차단되지 않도록 합니다.
  • 병렬 처리는 수집된 데이터를 여러 CPU 코어에서 동시에 처리하는 데 사용됩니다. 실시간 보고서를 제공함으로써 조직의 의사 결정 과정을 개선합니다.

결론

동시성과 병렬 처리는 애플리케이션 성능 향상을 위해 소프트웨어 개발에 활용되는 두 가지 핵심 개념입니다. 동시성은 여러 작업을 동시에 실행할 수 있게 하는 반면, 병렬 처리는 여러 CPU 코어를 활용하여 데이터 처리 속도를 높입니다. 각각 고유한 기능을 지니지만, 이를 통합하면 I/O 중심 및 CPU 중심 작업 모두를 가진 애플리케이션의 성능을 크게 향상시킬 수 있습니다.

Bright Data의 도구들( 웹 스크레이퍼 API, 웹 스크레이퍼 함수, 스크래핑 브라우저 등)은 이러한 기법을 최대한 활용하고 일반적인 웹 스크래핑 문제를 해결하도록 설계되었습니다. 비동기 작업을 통해 여러 소스에서 동시에 데이터를 수집하고, 병렬 처리를 통해 데이터를 신속하게 분석 및 정리합니다. 따라서 Bright Data처럼 동시성과 병렬 처리를 핵심에 이미 통합한 데이터 공급자를 선택하면 웹 스크래핑 시 이러한 개념을 처음부터 구현할 필요가 없어 시간과 노력을 절약할 수 있습니다.

지금 바로 무료 체험을 시작하세요!