본문 바로가기

코딩/파이썬

파이썬 쓰레드, 예제로 간단하게 알아보기

반응형

먼저 쓰레드를 한마디로 소개하자면,

쓰레드는 프로그램의 작업 단위입니다.


쓰레드를 이해하기 위해서는 우선 프로세스에 대해 인지하고 있어야 합니다.

 

프로세스는 우리가 실행하는 프로그램 자체를 의미합니다.

그리고 쓰레드는 프로세스 안에서 수행되는 작업의 단위를 의미합니다.

 

비유하자면 프로세스는 물건을 만들어내는 공장이고,

쓰레드는 물건을 만드는 일꾼입니다.

 

일꾼이 많으면 물건을 더 빨리, 많이 만들어낼 수 있고 공장의 작업효율은 올라갑니다.

마찬가지로 쓰레드가 여러개 존재하면 다중 작업을 더 빠르게 수행할 수 있고 프로세스의 동작 효율이 증가합니다.


그런데 기본적으로 파이썬은 하나의 프로세스에서 하나의 쓰레드만 사용합니다.

def for문():
    for i in range(5):
        print(i)

def print문():
	print("쓰레드테스트")
    
for문()
print문()

예시를 위해 test.py 파일을 생성하고 위와 같은 코드를 작성했습니다.

test.py를 실행하면 위 이미지와 같이 for문이 실행된 후에 print문이 실행됩니다.

test.py 프로세스에 쓰레드가 한 개 뿐이어서 print문과 for문을 동시에 수행할 수 없기 때문입니다.


우리는 오늘 2개의 쓰레드를 만들어서 print문과 for문을 각각의 쓰레드에 할당해주도록 하겠습니다.

import threading

def for문():
    for i in range(5):
        print(i)
def print문():
    print("쓰레드테스트")

쓰레드1 = threading.Thread(target= for문)
쓰레드2 = threading.Thread(target= print문)

쓰레드1.start()
쓰레드2.start()

쓰레드1.join()
쓰레드2.join()
import threading

파이썬의 기본라이브러리인 threading 라이브러리를 import 하면 쓰레드를 다룰 수 있습니다.

def for문():
    for i in range(5):
        print(i)
def print문():
    print("쓰레드테스트")

쓰레드1 = threading.Thread(target= for문)
쓰레드2 = threading.Thread(target= print문)

쓰레드를 생성하는 방법은 threading.Thread() 객체를 이용하면 됩니다.

저는 쓰레드1, 쓰레드2라는 이름의 쓰레드를 생성하고,

각각 for문 함수와 print문 함수를 할당해주었습니다.

쓰레드1.start()
쓰레드2.start()

생성된 쓰레드는 start() 함수를 이용해서 동작시킬 수 있습니다.

쓰레드1.join()
쓰레드2.join()

또한 쓰레드가 동작을 완료하기 전에 프로세스가 종료되지 않도록 join() 함수를 사용해줍니다.

이제 test.py를 실행하면 위와 같이 for문이 행되는 중간에 print문이 실행된 것을 확인할 수 있습니다.


여기까지 쓰레드에 대한 설명을 읽으셨다면 쓰레드가 많을수록 작업속도가 빨라지겠네? 라는 생각이 들 수 있습니다.

하지만 파이썬에는 GIL(Global Interpreter Lock)이라는게 있어서 여러개의 쓰레드가 동시에 동작할 수 없습니다.

앞서 살펴본 코드를 예시로 들자면 쓰레드2가 동작할 때 쓰레드1은 lock이 걸려 정지됩니다.

마찬가지로 쓰레드1이 동작할 때는 쓰레드2가 lock이 걸려 정지됩니다.

 

아니 그럼 쓰레드 1개를 쓰나 여러개를 쓰나 작업시간 차이가 없는데 왜 쓰레드 쓰나요? 라는 생각이 들수도 있습니다.

 

하지만 작업을 수행할 때 지연이 생기는 경우를 가정하면 GIL이 존재하더라도 다중 쓰레드 환경에서의 효율이 더 높습니다.

import threading
import time

def for문():
    for i in range(5):
        print(i)
        time.sleep(1)
def print문():
    print("쓰레드테스트")

쓰레드1 = threading.Thread(target= for문)
쓰레드2 = threading.Thread(target= print문)

쓰레드1.start()
쓰레드2.start()

쓰레드1.join()
쓰레드2.join()

예를 들어 위와 같이 time.sleep()을 이용해 for문 중간에 1초씩 딜레이를 준다면,

1초간의 딜레이가 존재하는 동안 쓰레드2에서 print문을 수행할 수 있습니다.

즉, 지연시간 동안 다른 작업을 수행할 수 있어서 효율이 증가하게 됩니다.

위 이미지를 보시면 0이 출력된 이후 바로 print문이 수행된 것을 확인할 수 있습니다.

참고로 time.sleep()을 쓰지 않고 테스트를 해보시면 위와 같이 print문의 수행 시점이 제멋대로인 것을 확인할 수 있습니다.

 

하지만 time.sleep()을 사용하고 테스트를 하면,

 for문의 최초 지연시간인 0이 출력된 직후에 무조건 print문이 수행되는 것을 확인할 수 있습니다.

반응형