(파이썬)멀티스레딩 질문입니다.

def fibo(n):
    if n <= 1:
        return n
    return fibo(n-1) + fibo(n-2)

def print_fibo(arr, arr_num):
    tot_time = 0
    for i in arr:
        s = time.time()
        print(f'[{arr_num}]fibonacci({i}) = {fibo(i)}')
        t_check = time.time()-s
        tot_time += t_check
        time.sleep(1)
    print(f'arr{arr_num} total time : {tot_time:.2f}s') 
    # sleep을 제외한 순수 fibonacci 계산시간(누적)

arr = [i for i in range(20, 41, 2)]
arr1 = [i for i in range(20, 41, 6)] # [20, 26, 32, 38]
arr2 = [i for i in range(22, 41, 6)] # [22, 28, 34, 40]
arr3 = [i for i in range(24, 41, 6)] # [24, 30, 36]


t1= Thread(target=print_fibo, args=(arr1, 1,))
t2= Thread(target=print_fibo, args=(arr2, 2,))
t3= Thread(target=print_fibo, args=(arr3, 3,))

멀티스레딩 성능을 테스트해보기 위한 실험을 해보았는데요,

일부러 함수 실행시간이 긴 재귀함수 fibo를 target으로 정했습니다.

sleep을 설정한 이유는 파이썬에서는 GIL 때문에 sleep한 시간동안 다른 스레드를 작동시키기 위해서입니다.

싱글스레드와 멀티스레드의 실행시간 차이는 제가 예상했던대로
싱글스레드 : 52초(sleep한 시간 포함)
멀티스레드 : 44초(sleep한 시간 포함)
이렇게 결과가 나왔습니다.

그런데 싱글스레딩에서는 순수계산시간이 41초로 측정되었고
멀티스레딩에서는 각 스레드에서 10초(t1), 23초(t2), 40초(t3) 총 73초로 측정되었습니다.

싱글이든 멀티든 fibonacci를 계산하는 양 자체는 동일할텐데,
왜 두 환경에서 계산시간 차이가 나는 것 처럼 보일까요?

제가 생각해본 이 이유를 설명하는 가설은 밑에 그림과 같습니다.

이 그림대로라면 thread1에서 fibo(34)을 계산하고, 1초의 sleep동안 thread2에서 fibo(36)을 계산합니다. 1초 뒤 thread2의 작업이 중단되고 다시 thread1로 돌아와 fibo(40)을 계산합니다. fibo(40)이 끝나면 thread2에서 남은 작업을 수행합니다.
즉 thread2의 total duration은 fibo(36) + fibo(40) 만큼이 되는겁니다.

나름 고민해서 생각해본 가설인데 제가 예상한 이유가 맞을까요? 아니라면 어떤 이유 때문에 둘의 차이가 발생할까요?

그리고 위와 같은 코드를 수행할 때 멀티스레딩을 더 효율적으로 할 수 있는 방법도 궁금합니다.

안녕하세요.

일단 파이썬의 쓰레드가 말씀하신대로 GIL이기 때문에 병렬성이 아니라 동시성을 갖습니다.
그리고 제가 알고있기로는 sleep하지않아도 알아서 스위칭을 하는걸로 알고있긴한데요.

https://docs.python.org/3/library/sys.html#sys.setswitchinterval

따라서 저렇게 시간을 측정하시면 안되겠죠?

일단 sleep하는걸 측정하는건 싱글일때는 아무것도안하는데 멀티스레드일때는 일을 하긴하니까 이상한 오차가 되는거구요. 그래서 멀티스레드가 더 느려야하는데 더 빠른 이상한 현상이 생기는거죠. 11초나 아무것도 안하고 쉬니까요.

sleep을 빼고 해보시면 아마도 멀티스레드가 더 느리거나 비슷하게 나올겁니다. 41s vs 44s 니까용 ㅎㅎㅎ

성능을 원하시면 코루틴같은걸 사용하셔서 필요하실때 계산하시거나, 멀티 프로세스를 사용하세요.
멀티 프로세스는 병렬성을 확보할 수 있습니다.

1 Like

그리고 위의 가설은 sleep할때만 컨텍스트 스위칭되는게 아니니 틀린것임을 알 수 있죠??

파이썬은 GIL 때문에 CPU-bound 작업을 잘 처리하지 못합니다
멀티프로세스가 그나마 대안이지만, 멀티스레딩에 비해 컨텍스트 스위칭 비용이 크죠

그래서 CPU-bound는 멀티스레딩을 지원하는 다른 언어에 넘기고,
IO-bound 작업들만 받아서 코루틴으로 처리하는 방식을 사용하시는 것이 좋습니다

Numpy나 여타 머신러닝 관련 라이브러리들도 내부 구현은 C/C++입니다

1 Like

파이썬 멀티스레딩으로는 여러 개의 함수를 동시에 연산시킬수는 있지만 병렬적으로는 하기 어려운 것 같네요.
답변 감사합니다 :fire: