반응형
GIL(global interpreter lock)
- 한 순간에 1개의 스레드만 유지하는 락
- GIL은 본질적으로 한 스레드가 다른 스레드를 차단해서 제어를 얻는 것을 막음
멀티스레딩의 위험으로부터 보호(하나의 메모리를 공유하므로 오류로 인해 전체가 다운될 수 있음) - 그러므로 파이썬은 스레드로 병렬성 연산을 수행하지 못함
- 파이썬 멀티 스레딩은 동시성을 사용하여 io bound 코드(네트워크)에서 유용하게 사용할 수 있음
- 하지만 동시성은 cpu bound 코드(연산만 있는)에서 이점이 없음
해결책
멀티 프로세싱으로 병렬성을 구현하여 효율을 높일 수 있음.
단, 프로세스끼리 메모리를 공유하지 않기 때문에 직렬화 역직렬화에 소요되는 비용이 큼
비교 실험
멀티스레딩 22초 <> 멀티프로세싱 13초
(하단 비교 코드 첨부)
결론
멀티스레딩은 cpu_bound 에서 의미가 없으며 오히려 스레드 생성 연산이 추가되므로 더 느려진다.
멀티 스레딩을 사용한 경우 ( 22 초 )
일반 계산과 차이가 없거나 더 느리다
from concurrent.futures import ThreadPoolExecutor
import time
import os
import threading
nums = [30] * 100
def cpu_bound_func(num):
print(f"{os.getpid()} process | {threading.get_ident()} thread")
numbers = range(1, num)
total = 1
for i in numbers:
for j in numbers:
for k in numbers:
total *= i * j * k
return total
def main():
executor = ThreadPoolExecutor(max_workers=10)
result = list(executor.map(cpu_bound_func, nums))
print(result)
if __name__ == "__main__":
start = time.time()
main()
end = time.time()
print(end - start)
멀티 프로세싱을 사용한 경우 ( 13 초 )
import time
import os
import threading
from concurrent.futures import ProcessPoolExecutor
nums = [30] * 100
def cpu_bound_func(num):
print(f"{os.getpid()} process | {threading.get_ident()} thread")
numbers = range(1, num)
total = 1
for i in numbers:
for j in numbers:
for k in numbers:
total *= i * j * k
return total
def main():
executor = ProcessPoolExecutor(max_workers=10)
result = list(executor.map(cpu_bound_func, nums))
print(result)
if __name__ == "__main__":
start = time.time()
main()
end = time.time()
print(end - start)
반응형
'나는 이렇게 학습한다 > Language' 카테고리의 다른 글
파이썬 range로 음수와 0도 반복할 수 있을까? (0) | 2022.02.10 |
---|---|
Overloading 과 Overriding 을 Python코드로 구현 (0) | 2022.02.07 |
파이썬 멀티 스레딩 (0) | 2022.01.16 |
파이썬 코루틴 활용 (0) | 2022.01.16 |
파이썬 코루틴 (0) | 2022.01.15 |