Python으로 Thread 구현하기.
Python에서의 병렬처리 방법 2020-04-10
주의! Caution!
해당 게시글은 Archive된 게시글 입니다.
Archive된 사유는 다음 중 하나에 해당 됩니다.
  • 작성 된지 너무 오랜 시간이 경과 하여, API가 변경 되었을 가능성이 높은 경우
  • 주인장의 Data Engineering으로의 변경으로 질문의 답변이 어려워진 경우
  • 글의 퀄리티가 좋지 않아 글을 다시 작성 할 필요가 있을 경우
이 점 유의하여 게시글을 참고 하시길 바랍니다.

Python Thread

Python에서는 한 프로세스에서 여러 가지 병렬 처리를 위해 Thread를 구현 할 수 있는 API를 제공 합니다.

프로그램을 여러 개로 나누지 않으며 하는 Thread Programming장점은 다음과 같습니다.

  • 전역 변수를 이용한 메모리 공유를 통해 효율적인 메모리 사용이 가능
  • 철저한 작업 분리 가능
  • 코드 간결성

하지만, 단점 또한 존재합니다.

  • 디버깅 난이도 상승
  • 구현 난이도 상승
  • 교착 상태가 발생하지 않도록 주의 하여야 함

진짜 이렇게 된다니까요?

Thread

일단 가장 기본적인 threading.Thread를 이용하는 방법 입니다. threading.Thread(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None) 객체의 생성자의 파라미터는 다음과 같습니다.

  • target: Threadrun() 함수를 통해 돌리고 싶은 함수를 넣는다. function을 인자로 받는다.
  • args: target으로 넣은 함수의 args 파라미터 값을 iterable 한 객체로 넣으면 된다.
  • kwargs: target으로 넣은 함수의 kwargs 파라미터 값을 dict 객체로 넣으면 된다.
  • name: Thread 객체의 이름을 정한다. 없으면 "Thread-N" 이라는 unique한 값으로 정해진다. (N은 숫자다.)
  • group: Thread를 그룹화 하여 실행할 때 사용 한다.
  • daemon: ThreadDaemon Thread로 만들고 싶을 때 사용 한다.

또한, threading.Thread 객체의 내부 멤버함수 입니다.

  • run(): Thread에 등록 된 함수를 실행합니다.
  • getName(), setName(): 스레드 이름의 getter/setter 함수 입니다.
  • is_alive(): 스레드가 실행 중인지를 반환 합니다.
  • isDaemon(), setDaemon(): 데몬 스레드를 지정하는 getter/setter 함수 입니다.

Example

예시 코드 입니다.

  • In
import threading, time

var = 0

def func(second):
	time.sleep(second)
	print("This Thread Used", second, "Second")

t = threading.Thread(target=func, args=(1,))
t.start()

print("Program end")

  • Out
Program end
This Thread Used 1 Second

Daemon Thread

만약 Thread메인 프로세스가 종료 되면 같이 종료되는 Daemon Thread라면 어떻게 될 까요?

  • In
import threading, time

var = 0

def func(second):
	time.sleep(second)
	print("This Thread Used", second, "Second")

t = threading.Thread(target=func, args=(1,), daemon=True)
t.start()

print("Program end")

  • Out
Program end

이렇게 메인 프로세스가 종료 됨에 따라서, Daemon Thread는 작동 하지 않게 됩니다.

Thread 정보 가져오기

Thread 정보는 해당 스레드에서 threading.current_thread()를 통해 Thread 객체를 가져오거나, threading.enumerate()를 통해 Thread 객체 list를 가져 올 수 있습니다.

  • In
import threading, time

var = 0

def func():
	time.sleep(0.3)
	print("Current thread: ", threading.current_thread().getName())

for _ in range(10):
	t = threading.Thread(target=func)
	t.start()

print(threading.enumerate())

  • Out
[<_MainThread(MainThread, started 139696403076928)>, <Thread(Thread-1, started 139696381187840)>, <Thread(Thread-2, started 139696372795136)>, <Thread(Thread-3, started 139696294328064)>, <Threa
d(Thread-4, started 139696285935360)>, <Thread(Thread-5, started 139696277542656)>, <Thread(Thread-6, started 139696269149952)>, <Thread(Thread-7, started 139696260757248)>, <Thread(Thread-8, st
arted 139696252364544)>, <Thread(Thread-9, started 139696243971840)>, <Thread(Thread-10, started 139695690348288)>]
Current thread:  Thread-1
Current thread:  Thread-2
Current thread:  Thread-3
Current thread:  Thread-4
Current thread:  Thread-5
Current thread:  Thread-7
Current thread:  Thread-8
Current thread:  Thread-6
Current thread:  Thread-9
Current thread:  Thread-10

마치며

훌륭한 프로그래머는 병렬 프로그래밍에 대해도 익숙해 져야 합니다. 생각해보면, 스레드는 가장 가까운 곳에도 있습니다. 서버 프로그래밍이나, GPU를 이용한 딥 러닝 학습 등 많은 곳에서 사용됩니다. 더 쉬운 설명을 원한다면, 해당 링크에서 영상을 시청 해 주세요.