멀티 스레딩(Multi Thread)
멀티 스레딩(Multi Thread)
한 번에 여러 작업을 동시에 처리하기 위해 사용되는 프로그래밍 기법이다. 멀티 스레딩을 통해 여러 작업을 병렬로 실행하여 시스템 자원을 효율적으로 활용할 수 있다.
스레드(Thread)
프로세스 내에서 실행되는 작은 실행 단위. 하나의 프로세스는 여러 개의 스레드를 가질 수 있으며, 각각의 스레드는 독립적으로 실행될 수 있다. 스레드는 프로세스 내의 자원을 공유하면서 동시에 실행될 수 있으므로, 여러 작업을 동시에 처리할 수 있게 된다.
프로세스(Process)
운영체제에서 실행 중인 프로그램을 의미한다.
각 프로세스는 독립적인 메모리 공간을 가지며, 운영체제에 의해 관리된다. 프로세스는 하나 이상의 스레드를 포함할 수 있다.
프로세스는 프로그램의 실행 인스턴스로써, 코드, 데이터, 메모리 등의 리소스를 할당받아 동작한다. 각 프로세스는 독립적으로 실행되며, 서로 영향을 주지 않고 병렬로 실행될 수 있다. 이러한 프로세스간의 독립성은 안정성과 보안성을 제공하면서, 동시에 여러 작업을 처리할 수 있는 장점을 갖고 있다.
멀티 스레딩에서는 하나의 프로세스 내에서 여러 개의 스레드가 동작할 수 있다. 스레드는 프로세스 내에서 실행되는 독립적인 실행 흐름을 가지며, 같은 프로세스 내의 스레드들은 동일한 메모리 공간을 공유한다. 이로 인해 스레드 간 데이터 공유가 간편하고, 스레드 간의 통신이 빠르게 이루어질 수 있다.
프로세스와 스레드는 각각의 장단점과 사용 용도가 있다. 프로세스는 안정성과 독립성이 높아 병렬 처리를 위한 독립적인 환경이 필요한 경우에 적합하다. 반면에 스레드는 경령화된 실행 단위로, 동시에 여러 작업을 처리하고 데이터를 공유하는 경우에 유용하다. 따라서 상황과 요구사항에 맞게 프로세스와 스레드를 적절히 활용하는 것이 중요하다.
멀티 스레딩 장점
동시성(Concurrency)
여러 작업을 동시에 실행하여 처리 속도를 향상시킬 수 있다. 작업을 병렬로 처리함으로써 시간을 절약할 수 있다.
응답성(Responsiveness)
한 작업이 다른 작업에 의해 차단되지 않고 동시에 실행될 수 있으므로, 프로그램이 더 빠르게 응답할 수 있다. GUI 애플리케이션에서는 사용자 입력을 받는 동안에도 백그라운드에서 다른 작업을 처리할 수 있다.
자원 공유(Resource Sharing)
스레드 간에 메모리 등의 자원을 공유할 수 있다. 데이터를 효율적으로 공유하고 작업을 조율할 수 있다.
간단한 통신(Simplified Communication)
스레드 간에 간단한 통신을 할 수 있다. 스레드는 메모리 공간을 공유하므로, 변수 등을 통해 데이터를 주고받을 수 있다.
[Python] threading 모듈
파이썬에서는 'threading' 모듈을 사용하여 멀티 스레딩을 구현할 수 있다. 이 모듈은 스레드 생성, 스레드 동기화, 스레드 간 통신 등을 지원한다.
실행단계
- threading 모듈을 임포트한다.
- 스레드로 실행할 함수나 메소드를 정의한다.
- Thread 클래스의 인스턴스를 생성하고, 실행할 함수나 메소드를 매개변수로 전달한다.
- 스레드를 시작하고 실행한다.
- 필요에 따라 스레드 간 동기화를 위해 락(lock) 등의 도구를 사용한다.
- 스레드의 실행이 완료되면 정리 작업을 수행한다.
import threading
# 실행할 함수 정의
def print_numbers():
for i in range(1, 6):
print(i)
def print_letters():
for letter in 'ABCDE':
print(letter)
# 스레드 생성 및 실행
t1 = threading.Thread(target=print_numbers)
t2 = threading.Thread(target=print_letters)
t1.start()
t2.start()
# 스레드가 종료될 때까지 기다림
t1.join()
t2.join()
print("모든 작업이 완료되었습니다.")
print_numbers 함수와 print_letters 함수는 각각 숫자를 출력하고 알파벳을 출력하는 역할을 한다. threading.Thread 클래스를 사용하여 스레드를 생성하고, target 매개 변수에 실행할 함수를 지정한다. start() 메소드를 호출하여 스레드를 실행하고, join()메소드를 사용하여 스레드의 실행이 완료될 때까지 기다린다. 모든 작업이 완료되면 print()문을 실행한다.
주의사항
스레드 간에 자원을 공유하면서 동시에 접근할 경우 동기화 문제가 발생할 수 있으며, 이로 인해 예기치 않은 결과가 발생할 수 있다.
이를 해결하기 위해 스레드 동기화 기법인 락(lock)을 사용하거나, 스레드 간의 통신을 조율하는 방법을 적절히 사용해야 한다.
또한, 파이썬에서 멀티 스레딩은 GIL(Global Interpreter Lock)라는 제약 사항이 있어서 CPU-bound 작업에 대해서는 병렬 처리 효과를 기대하기 어렵다. 따라서 CPU-bound 작업을 처리하는 경우에는 멀티 프로세스(Multi-Processing)기법을 고려해야한다.
멀티 스레딩은 I/O-bound 작업이나 동시성을 요구하는 작업을 처리하는 데 효과적이다.
CPU 바운드 작업
CPU 바운드 작업은 작업의 수행 시간의 대부분을 CPU 연산에 소비하는 작업을 의미한다. 이는 주로 계산 작업이나 복잡한 알고리즘을 수행하는 작업을 말한다. 예를 들면 숫자 계산, 데이터 분석, 이미지 처리 등이 있다. CPU 바운드 작업에서는 CPU 자원이 주요 bottleneck(병목)으로 작용하여 작업의 속도를 결정한다.
GIL(Global Interpreter Lock)
GIL(Global Interpreter Lock)은 CPython(파이썬의 표준 구현체)에서 사용되는 메커니즘이다. GIL은 파이썬 인터프리터의 스레드 간 동기화를 담당한다. 파이썬의 GIL은 여러 스레드가 동시에 파이썬 바이트코드를 실행하는 것을 제어하여 스레드 간의 충돌을 방지한다. 즉, GIL은 동시에 하나의 스레드만 파이썬 바이트코드를 실행할 수 있도록 제한한다.
GIL의 존재로 인해 파이썬의 멀티 스레딩이 실제로 병렬 처리를 이뤄내지 못하는 경우가 발생한다. GIL은 여러 스레드가 동시에 CPU를 활용하는 것을 제한하므로 CPU 바운드 작업에서는 멀티 스레딩으로 성능 향상을 기대하기 어렵다. 하지만 I/O 작업과 같은 블로킹 작업(네트워크 요청, 파일 입출력 등)에서는 GIL의 영향을 덜 받기 때문에 멀티 스레딩을 통해 병렬화할 수 있다.
GIL은 CPython에서만 존재하며, 다른 파이썬 인터프리터인 Jython, IronPython 등에서는 GIL이 없다. 따라서 이러한 인터프리터를 사용하면 멀티 스레딩을 통해 CPU 바운드 작업을 병렬 처리할 수 있다.
Cpython
파이썬의 표준 구현체 중 하나로, 파이썬 언어를 C 언어로 구현한 인터프리터이다. 일반적으로 사용하는 파이썬이다.