Python은 GIL(Global Interpreter Lock)에 의해 원칙적으로는 하나의 인터프리터가 어떤 시점에 하나의 스레드에서만 실행될 수 있다. 다만 우회 아닌 우회(?)를 이용해 멀티쓰레딩을 모방하여 사용할 수 있다. 여러 개의 스레드를 한번에 실행하는 게 아니라 여러 스레드를 그때 그 시점마다 옮겨 다니며(context-switching) 실행하는 것인데, 자세한 설명은 생략한다. 아래 그림을 참고하자.
기본 CPython 구현체를 사용하며 Python에서 병렬 작업을 수행하는 방법으로는 크게 3가지가 있다. (다른 Python 인터프리터 구현체를 사용하는 방법도 있으나 그건 서술하지 않는다.)
- asyncio 이용 (Python 3.7 이후부터 await, async 키워드와 asyncio가 지원되는 것으로 알고 있다.)
- multithreading 이용
- multiprocessing 이용
multiprocessing은 멀티프로세스를 사용하지만 나머지 둘은 멀티쓰레딩을 사용하는 것으로 알고 있다. 당연히 그때 그때 상황에 따라 달라지지만, CPU-intensive한 작업을 한다면 멀티프로세싱, I/O-intensive한 작업을 한다면 멀티스레딩을 쓰라고 말하는 게 일반적이다.
JS 등 asynchronous한 언어에서 await, async 키워드를 써오던 유저라면 asyncio가 굉장히 편리할 것이고, 나머지는 그때 그때 상황에 따라 맞춰 쓰면 된다. 이러한 내용에 대해 이론적으로 깊은 설명을 하려고 쓴 글은 아니고 단순히 ThreadPool의 좋은 예시를 발견해 쓴 글이기에 자세한 내용은 생략한다.
보여주고 싶은 예시는 아래와 같다.
https://github.com/open-mmlab/mmdetection/blob/master/tools/misc/download_dataset.py
if threads > 1:
pool = ThreadPool(threads)
pool.imap(lambda x: download_one(*x), zip(url, repeat(dir)))
pool.close()
pool.join()
개인적인 경험으로 여러 쓰레드가 필요할 때는 같은 작업(다운로드 등)을 수행하는 여러 개의 스레드가 필요한 경우가 많았는데, 이럴 때 ThreadPool을 이용해 여러 스레드를 동시에 만들어 map_async 등 함수를 동시에 적용하는 게 가장 편리했다.
직접 실행해보면 위와 같이 병렬적으로 빠르게 다운로드가 되는 것을 확인할 수 있다.
'프로그래밍 언어 > Python' 카테고리의 다른 글
[Pyside6] stdout, stderr TextBrowser에 출력되게 하기 (0) | 2022.07.22 |
---|