개발

멀티 프로세싱 & 멀티 스레딩 & 비동기 처리

31514 2024. 10. 2. 13:22

이 글은 파이썬에서 멀티 프로세싱, 멀티 스레딩, 비동기 처리를 적재적소에 사용하기 위해 각각의 개념과 적합한 경우를 알아보는 글이다.

 

멀티 스레딩

<개념>

멀티 스레딩은 하나의 프로세스 안에서 여러 개의 스레드를 동시에 실행하는 방식이다.

스레드는 동일한 메모리 공간을 공유하지만, 독립적으로 실행될 수 있다.

 

<적합한 경우>

멀티 스레딩은 주로 I/O 바운드 작업에 적합하다.

I/O 바운드 작업은 네트워크 요청, 파일 읽기/쓰기 등을 말한다.

 

<이유>

파이썬에서 멀티 스레딩이 CPU 바운드 작업이 적합하지 않은 이유는 GIL(Global Interpreter Lock) 때문이다.

파이썬은 모든 것이 객체로 동작하고, 각 객체는 참조 횟수(Reference Count)를 저장하기 위한 필드를 가지고 있다.

파이썬의 객체는 어디서 참조되느냐에 따라 그 객체에 대한 참조 횟수가 증가하거나 감소하며, 참조 횟수가 0이 되는 시점에 메모리에서 해제된다.

만약에 멀티 스레딩 환경에서 여러 스레드가 같은 참조 횟수에 접근하면 올바른 값을 가질 수 없는 경쟁 조건(Race Condition)이 발생한다.

이를 막기 위해서 파이썬은 경쟁 조건을 예방하는 알고리즘 중 하나인 뮤텍스(Mutex)를 도입했다.

따라서 멀티 스레딩 프로그램이 CPU의 멀티 코어에서 병렬 실행된다고 한들, 컨텍스트 스위칭만 발생할 뿐 실제로 병렬 처리되지 않는다.

 

하지만 이는 CPU 바운드 작업일 경우에만 해당된다.

CPU 코어를 사용하지 않는 외부 연산(I/O 바운드 작업, Sleep 등)은 멀티 스레딩을 사용하면 성능 향상을 기대할 수 있다.

 

멀티 프로세싱

<개념>

멀티 프로세싱은 여러 개의 프로세스를 동시에 실행하여 작업을 병렬로 처리하는 방법이다.

각각의 프로세는 독립된 메모리 공간을 사용하며, CPU 코어를 활용해 병렬 처리한다.

 

<적합한 경우>

멀티 프로세싱은 주로 CPU 바운드 작업에 적합하다.

CPU 바운드 작업은 복잡한 계산, 데이터 처리와 같이 리소스를 많이 사용하는 작업을 말한다.

 

<이유>

멀티 프로세싱은 멀티 스레딩과 다르게 독립된 메모리 공간을 사용하기 때문에 GIL을 신경쓰지 않아도 된다.

따라서 CPU를 주로 사용하는 CPU 바운드 작업을 병렬로 처리할 수 있다.

 

반대로 멀티 프로세싱에서 I/O 작업은 어떨까?

▶ I/O 작업은 주로 CPU 연산을 적게 하고 입출력 대기에 의한 지연 시간이 많기 때문에 CPU 자원이 낭비될 수 있다.

그리고 멀티 프로세싱을 사용하면 프로세스 간의 메모리 복사프로세스 관리 비용이 발생하는데, I/O 바운드 작업에서는 이러한 오버헤드가 성능에 부정적인 영향을 줄 수 있다.

 

그럼 멀티 스레딩이야 비동기 처리야?

멀티 스레딩은 여러 개의 스레드에서 동시에 작업을 수행한다.

비동기 처리는 하나의 스레드에서 동시적으로 작업을 수행한다.

 

그럼 하나의 스레드에서 빠른 Context Switching으로 마치 동시에 실행하는 것처럼 보이게 하는 비동기 처리의 성능이 더 낮은 거 아닌가?

▶ 비동기 처리에서의 Context Switching은 OS의 프로세스/스레드 Context Switching과 다르다. 비동기 처리에서는 코루틴 간의 전환이 일어난다. 따라서 OS의 스케줄러가 아니라 asyncio의 이벤트 루프가 이를 관리하고, 코루틴 내부의 실행 위치만 변경하므로 비용이 매우 적다.

 

만약 파이썬의 비동기 프로그래밍에 대해 더 알고 싶다면, 이 블로그를 참조하면 좋을 거 같다.

 

따라서 멀티 스레딩과 비동기 처리 모두 I/O 바운드 작업에 적합하고, 어떤 것을 사용할지는 개인 취향이라고 생각하면 될 거 같다.