바운드

  • Bound의 뜻: 경계, 한계
  • 프로세스 진행이 제한되는 것을 의미한다. 원인에 따라 분류해보면 다음과 같다.

CPU 바운드

  • 프로세스 진행 속도가 CPU 속도에 의해 제한됨을 의미한다.(CPU Burst가 큰 프로세스)
  • 복잡한 수학 수식을 계산하는 경우 프로그램의 실행속도가 느려진다.
  • 동영상 편집, 머신러닝 등

버스트(Burst)란

  • 어떤 현상이 짧은 시간 안에 집중적으로 일어나는 일

I/O 바운드

  • 프로그램이 실행될 때 실행 속도가 I/O에 의해 제한됨을 의미한다.(I/O Burst가 큰 프로세스)

  • 사용자가 입력을 하고 해당하는 입력에 대해 더하기 100을 한 결과값을 출력해주는 프로그램이 있다면 사용자가 입력을 하는 데 걸리는 시간에 따라서 프로그램의 실행 속도가 결정된다.

  • 인터넷에서 사진을 수집해서 저장하는 프로그램은 인터넷 속도가 전체 프로그램의 성능을 결정한다.

  • 컴퓨터끼리 통신을 할 때에도 I/O바운드가 발생한다.

  • 예시: 일반적인 백엔드 API, 파일을 읽거나 쓰는 작업 등

메모리 바운드

  • 프로세스가 진행되는 속도가 사용 가능한 메모리 양과 해당 메모리 액세스 속도에 의해 제한됨을 의미한다.

  • 많은 양의 메모리 데이터를 처리하는 작업 (큰 행렬 곱하기 등)은 메모리 바운드 일 가능성이 높다.

캐시 바운드

  • 프로세스 진행률이 사용 가능한 캐시의 양과 속도에 의해 제한되는 비율을 의미한다.
  • 캐시에 맞는 것보다 더 많은 데이터를 단순히 처리하는 작업은 캐시에 바인딩된다.

I/O 바운드는 메모리 바운드보다 느리고 캐시 바운드는 CPU 바운드보다 느리다.
I/O 바인딩 솔루션은 반드시 더 많은 메모리를 확보 할 필요는 없다.
경우에 따라 액세스 알고리즘은 I/O, 메모리 또는 캐시 제한을 중심으로 설계 될 수 있다.

블로킹 vs 논 블로킹

  • 블로킹: 어떤 작업을 하는 동안 다른 작업을 못하게 막는 것을 의미한다. 따라서 블로킹은 직렬로 실행될 수 밖에 없다.
  • 논 블로킹: 다른 작업에 상관없이 작업이 실행되는 것이다.

동기 vs 비동기

동기

  • 코드가 동기적으로 동작한다. -> 코드가 반드시 작성된 순서 그대로 실행된다.
  • 세 군데에 짜장면 배달을 갔는데 간 곳마다 손님이 짜장면을 다 먹을 때 까지 기다렸다가 그릇을 수거하고 다음 목적지로 배달하러 간다면 이는 동기적으로 일을 처리한 것이다.
  • 중간에 모여서 정보를 교환하고 일관성을 유지하는 작업을 한다. 따라서 일을 빨리 끝낸 쓰레드나 프로세스가 대기해야 하므로 시간 낭비가 발생할 수 있다.

비동기

  • 코드가 비동기적으로 동작한다. -> 코드가 반드시 작성된 순서 그대로 실행되는 것이 아니다.
  • 세 군데에 짜장면 배달을 갔는데 일단 배달부터 먼저 하고 손님이 다 먹은 후 그릇을 수거한다면 이는 비동기적으로 일을 처리 한 것이다.
  • 각 작업을 완전히 독립적으로 진행하므로 대기할 필요가 없다.
  • 동시성이나 병렬성 구현 시 일반적으로 비동기식이 효율이 좋지만 알고리즘에 따라서 동기식이 나을 수도 있다.

루틴

  • 일련의 명령, 코드의 흐름을 의미한다(프로그램의 순서).

메인 루틴

  • 프로그램의 메인 코드의 흐름

서브루틴

  • 메인 루틴에 종속된 루틴.
  • 우리가 알고 있는 일반적인 함수나 메서드(메인 루틴을 보조하는 역할).
  • 하나의 진입점과 하나의 탈출점이 있는 루틴이다.
  • 프로그램이 실행되면 서브 루틴은 별동의 공간(스코프)에 해당 로직들을 모아 놓고 있다.
  • 서브 루틴이 호출될 때, 해당하는 로직들의 공간으로 이동했다가 return을 통해 원래 호출시점(메인 루틴)으로 돌아오게 된다.
# 서브루틴의 예시
def subroutine():
	print("ABC")
    
def main():
	print("123")
    subroutine()
    print("456")
    subroutine()
	print("789")

코루틴

  • 다양한 진입점과 다양한 탈출점이 있는 루틴.
  • 코루틴은 서브 루틴과는 달리 해당 로직들이 진행되는 중간에 멈추어서 특정 위치로 돌아 갔다가 다시 코루틴에서 진행되었던 위치로 돌아와 나머지 로직을 수행할 수 있다.
  • 파이썬 비동기 함수는 코루틴 함수로 만들 수 있다.
# 코루틴의 예시
def coroutine():
	print("ABC")
    yield
    print("DEF")
    yield
    print("GHI")
    yield

def main():
	coro = coroutine()
    print("123")
    next(coro)
    print("456")
    next(coro)
    print("789")
    next(coro)

프로세스와 스레드

프로세스

  • 프로그램: 어떤 문제를 해결하기 위해 컴퓨터에게 주어지는 처리 방법과 순서를 기술한 일련의 명령문(코드)의 집합체
  • 프로그램 실행 -> 해당 프로그램의 작성된 코드들이 주 메모리로 올라와서 작업이 진행된다.
  • 프로그램은 저장장치에 저장된 정적인 상태이다.
  • 프로세스란 실행을 위해 프로그램이 주 메모리에 올라온 동적인 상태를 말한다.
  • 프로세스가 생성되면 CPU는 프로세스가 해야할 작업을 수행한다.

스레드

  • 프로세스가 생성되면 CPU는 프로세스가 해야할 작업을 수행한다. 이 때 CPU가 처리하는 작업의 단위가 바로 스레드 이다.
  • 즉 스레드란 프로세스 내에서 실행되는 여러 작업의 단위이다.
  • 스레드는 사용자 수준 스레드와 커널 수준 스레드로 나뉜다.
  • 스레드가 한 개로 동작하면 싱글 스레드, 여러 개로 동작하면 멀티 스레딩이라 한다.
  • 멀티 스레딩에서 스레드는 다수의 스레드들 간 메모리 공유와 통신이 가능하다.
  • 멀티 스레딩은 자원의 낭비를 막고 효율성을 향상시키지만 한 스레드에 문제가 생기면 전체 프로세스에 영향을 미친다는 단점도 있다.
  • 파이썬의 asyncio는 싱글 스레드로 동작한다.

동시성(병행성) vs 병렬성

동시성(Concurrency)

  • 동시성이란 한 번에 여러 작업을 동시에 다루는 것을 의미한다.

  • 여러 개의 일들이 동시에 진행되는 것 처럼 처리하는 것을 말한다.

  • 동시성은 논리적 개념으로 멀티 스레딩에서 사용되기도 하고 싱글 스레드에서 사용되기도 한다. 또한 싱글 코어 뿐만 아니라 멀티 코어에서도 각각의 코어가 동시성을 사용할 수 있다.

  • 동시에 작동하는 것 처럼 빠르게 여러 프로그램을 돌아가면서 작업을 처리하는 것이지 실제로 모든 작업이 동시에 실행되고 있는 것은 아니다.

  • 예를 들어 라면, 케이크, 파스타 주문이 한꺼번에 들어온 상황에서 라면 물을 끓이는 동안 케이크 반죽을 만들고 파스타 재료를 손질하고 다시 라면을 요리하는 방식이다.

  • 이렇게 여러 작업을 번갈아서 하기 때문에 컨텍스트 스위칭이 필요하다.

  • 주로 I/O 바운드에 사용된다.

병렬성(Parallelism)

  • 병렬성은 한 번에 여러 작업을 병렬적으로 처리하는 것을 의미한다. 동시에 여러 태스크를 처리하는 것이다.

  • 병렬성은 물리적 개념으로 멀티코어에서 여러 작업을 병렬적으로 수행한다.

  • 라면, 케이크, 파스타 주문이 한꺼번에 들어온 상황에서 세 명의 각기 다른 요리사가 요리를 시작하는 방식

  • 멀티 코어 단위에서 동작할 수 있지만 스레드 단위에서도 동작할 수 있다.

  • 병렬성과 동시성은 공존할 수 있다.

  • 파이썬에선 GIL(Global Interpreter Lock)으로 인해 멀티 스레딩으로 병렬성 작업을 수행할 수 없다.

  • 주로 CPU 바운드에 사용된다.

파이썬 멀티 스레딩 & 멀티 프로세싱

멀티 스레딩의 단점

  • 멀티 스레딩은 스레드끼리 자원을 공유한다. 그런데 하나의 자원을 동시에 여러 스레드가 가져가려는 상황에선 충돌이 발생할 수 있다. 이 경우 하나의 스레드가 다른 스레드에 의해 차단될 수 있다.
  • 파이썬 GIL은 이러한 문제점을 막는다.

전역 인터프리터 잠금(GIL, Global Interpreter Lock)

  • GIL이란 CPython에서 한 번(한 순간)에 한 개의 스레드만 유지하는 잠금장치이다.
  • GIL은 기본적으로 한 스레드가 다른 스레드를 차단하여 제어를 얻지 못하도록 한다.
  • GIL에 의해서 파이썬으로는 스레드가 병렬적인 연산을 수행하기 어렵다.
  • 다른 언어에서는 멀티스레딩을 동시성과 병렬성에 모두 활용할 수 있지만 파이썬은 현실적으로 동시성에만 활용 가능하다.
  • 파이썬 멀티스레딩은 동시성을 이용하여 IO 바운드 코드에서 유용하게 사용할 수 있지만 CPU 바운드 코드에 대해서는 GIL에 의해 원하는 결과를 얻기 어렵다.
  • 따라서 파이썬으로 병렬성 연산을 수행하는 방법으로는 코루틴이 추천된다.
  • C++ 등 적합한 언어로 만든 모듈을 파이썬에서 활용하면 멀티스레딩을 자유롭게 사용 할 수 있다.
  • GIL은 GPU 멀티스레딩에는 영향을 주지 않는다.
  • 파이썬 3.13 부터는 GIL을 해제할 수 있다.

멀티 프로세싱의 장점

  • 멀티 프로세싱으로 이러한 멀티 스레딩을 단점을 보완할 수 있다.

멀티 프로세싱의 단점

  • 프로세스 간 메모리를 공유하지 않기 때문에 서로 통신을 해야 하며, 그에 대한 비용이 있다.

멀티스레딩 vs 멀티프로세싱 vs 파이썬 AsyncIO(코루틴) 비교

문제예시전략멀티스레딩멀티프로세싱Asyncio
I/O 바운드웹 스크래핑동시성O\triangleO
CPU 바운드수학 계산병렬성X (GIL)OX
  • 이 중 두 가지 혹은 세 가지를 함께 사용할 수도 있다.

참고자료

0개의 댓글