파이썬은 기본적으로 하나의 스레드에서 실행되어, 하나의 메인 스레드에서 파이썬 코드를 순차적으로 실행한다. 코드를 병렬로 실행하기 위해서는 별도의 스레드를 생성하여야 하는데, threading 모듈을 사용하면 된다.
파이썬은 GILGlobal Interpreter Lock 때문에 특정 시점에 하나의 코드만을 실행하게 된다. 다중 CPU에서 파이썬 코드를 병렬로 실행하기 위해서는 다중 프로세스를 이용하는 multiprocessing 모듈을 사용한다.
파이썬에서 스레드를 실행하기 위해서는, threading 모듈의 threading.Thread() 함수를 호출하여 Thread 객체를 얻은 후 Thread 객체의 start() 메서드를 호출하면 된다.
객체 | 설명 |
---|---|
Thread | 단일 실행 스레드를 만드는 객체 |
Lock | 기본적인 락 객체 |
RLock | 재진입 가능한 락객체. 이미 획득한 락을 다시 획득 할 수 있다. |
Condition | 다른 스레드에서 신호를 줄 때까지 기다릴 수 있는 컨디션 변수 객체 |
Event | 컨디션 변수의 일반화 버전. |
Semaphore | 정해놓은 갯수만큼의 스레드를 허용하는 동기화 객체. (예를들어 최대 50개만 동시에 실행) |
BoundedSemaphore | 초기 설정된 값 이상으로 증가 될 수 없게 재한한 Semaphore |
Timer | Thread 와 비슷하지마 실행되기 전에 지정된 시간 동안 대기 |
Barrier | 스레드들이 계속 진행 할 수 있으려면 지정된 숫자의 스레드가 해당 지점까지 도달해야하게 만듬 (파이썬 3.2에서 처음 소개됨) |
Thread(name=, target=, args=, kwargs=, *, daemon=)
스레드 객체를 생성했다 하더라도 해당 스레드가 바로 시작되지는 않는다. start()를 호출하면 스레드가 그때부터 시작된다.
스레드가 실행할 함수를 작성하고 그 함수명을 threading.Thread() 함수의 target 아규먼트로 전달하면 된다.
만약 스레드가 실행할 함수에 파라미터를 전달해야 한다면, threading.Thread()의 args(혹은 kwargs)에 지정해주면 된다.
args는 tuple로 파라미터를 전달하고, kwargs는 dict로 전달한다.
아래의 예제를 보면 executeThread함수를 target으로 지정하였고, args에 튜플로 파라미터를 지정해주었다.
주의할 점은 target = executeThread() 처럼 지정하면 이는 executeThread() 함수를 실행하여 리턴한 결과를 target에 지정하는 것이므로 잘못된 결과가 나올 수 있다.
import threading
import urllib.request
import time
def executeThread(i):
imageName = f"temp/image-{str(i)}.jpg"
urllib.request.urlretrieve("https://test.com/test.jpg", imageName)
def main():
t0 = time.time()
threads = []
for i in range(10):
thread = threading.Thread(target=executeThread, args=(i,))
threads.append(thread)
thread.start()
for i in threads:
print("i ::: ", i)
i.join()
t1 = time.time()
totalTime = t1- t0
print("Total Execution Time {}".format(totalTime))
if __name__ == "__main__":
main()
Thread 클래스를 파생하여 쓰레드가 실행할 run() 메서드를 재정의해서 사용하는 방식.
Thread 클래스에서 run() 메서드는 스레드가 실제 실행하는 메서드이며, start() 메서드는 내부적으로 이 run() 메서드를 호출한다.
import threading
# threading.Thread를 상속받는 클래스를 만들어서 run하여 객체를 생성한다.
class Messenger(threading.Thread):
def run(self):
for _ in range(10):
print(threading.currentThread().getName())
send = Messenger(name="Sending out Messages")
receive = Messenger(name="Receiving Messages")
send.start()
receive.start()