관리 메뉴

HAMA 블로그

파이썬 동시성 프로그래밍 - (1) 쓰레드 본문

Python

파이썬 동시성 프로그래밍 - (1) 쓰레드

[하마] 이승현 (wowlsh93@gmail.com) 2017. 4. 27. 16:07

연재 순서 

1. threading
2. Condition & Semaphore
3. Queue
4. multiprocessing
5. 비동기 (gevent) 
6. 분산 (celery)
7. GPGPU (PyCUDA)
8. 코루틴,asyncio,async/awiat
9. concurrent.future

1. 쓰레드 

파이썬에서의 쓰레드는 보통 Thread 혹은 Threading 모듈을 사용할 수 있다. 
또한 Queue 모듈을 통해서 생산자-소비자 패턴을 구현한다. 여러가지 이유로 Thread 보다는 Threading 모듈을 사용하길 추천한다.따라서 이 글에서는 Threading 과 Queue 에 대해서 알아본다.

daemon 

파이썬에서 thread 는 기본적으로 daemon 속성이 False 인데, 메인 쓰레드가 종료되도 자신의 작업이 끝날 때까지 계속 실행된다. 부모가 종료되면 즉시 끝나게 하려면 True 를 해줘야한다. 데몬속성은 반드시 start 이전에 호출되어야 한다. 

Threading 

Threading 모듈은 아래와 같은 객체들을 가지고 있다.

 객체

 설명 

Thread 

단일 실행 쓰레드를 만드는 객체 

Lock 

기본적인 락 객체 

RLock 

재진입 가능한 락객체. 이미 획득한 락을 다시 획득 할 수 있다. 

Condition 

다른 쓰레드에서 신호를 줄 때까지 기다릴 수 있는 컨디션 변수 객체  

Event 

컨디션 변수의 일반화 버전. 

Semaphore 

정해놓은 갯수만큼의 쓰레드를 허용하는 동기화 객체. (예를들어 최대 50개만 동시에 실행) 

BoundedSemaphore 

초기 설정된 값 이상으로 증가 될 수 없게 재한한 Semaphore 

Timer 

Thread 와 비슷하지마 실행되기 전에 지정된 시간 동안 대기  

Barrier 

쓰레드들이 계속 진행 할 수 있으려면 지정된 숫자의 쓰레드가 해당 지점까지 도달해야하게 만듬 (파이썬 3.2에서 처음 소개됨) 


Thread 클래스

 메소드 / 속성

 설명 

 daemon

 데몬쓰레드인지 - 기본은 False, 즉 부모쓰레드가 종료되도 살아있다. 

  __init__(group,target,name,args,kwargs={},verbose,daemon) 

 객체를 초기화한다

 start()

 쓰레드를 실행한다.

 run()

 쓰레드의 기능을 정희하는 메소드 (상속해서 오버라이드됨)  

 jon(timeout=None)

 쓰레드가 종료될때까지 대기한다.


Thread 생성방식

1. 함수를 전달해서

import threading
from time import sleep, ctime

loops = [8,2]

def loop(nloop,nsec):
print 'start loop', nloop, 'at:',ctime()
sleep(nsec)
print 'loop', nloop, 'at:', ctime()


def test() :
print 'starting at:', ctime()
threads = []
nloops = range(len(loops))

for i in nloops:
t = threading.Thread(target=loop,args=(i, loops[i]))
threads.append(t)

for i in nloops:
threads[i].start()

for i in nloops:
threads[i].join()

print 'all Done at: ', ctime()

if __name__ == '__main__'

test()

하나는 8초, 하나는 2초동안 실행되는 2개의 쓰레드를  threading.Thread 에 함수를 지정해서 실행한다. 

2. 상속을 통해 

import threading
from time import sleep, ctime

loops = [8,2]

class MyThread(threading.Thread):
def __init__(self,func,args,name=''):
threading.Thread.__init__(self,name=name)
self.func = func
self.args = args

def run (self):
self.func(*self.args) # 함수를 받아서 처리하는게 아니라 여기에 직접 구현하는 경우가 일반적..

def loop(nloop,nsec):
print 'start loop', nloop, 'at:',ctime()
sleep(nsec)
print 'loop', nloop, 'at:', ctime()


def test() :
print 'starting at:', ctime()
threads = []
nloops = range(len(loops))

for i in nloops:
t = MyThread(loop, (i,loops[i]),loop.__name__)
threads.append(t)

for i in nloops:
threads[i].start()

for i in nloops:
threads[i].join()

print 'all Done at: ', ctime()

if __name__ == '__main__'

 test()

threading.Thread 를 상속받은 클래스에 run 함수를 오버라이드하여 사용한다.

threading.Thread.__init__ 를 반드시 해야한다.


레퍼런스:

코어 파이썬 어플리케이션 프로그래밍

http://stackoverflow.com/questions/7424590/threading-condition-vs-threading-event

http://www.bogotobogo.com/python/Multithread/python_multithreading_Synchronization_Condition_Objects_Producer_Consumer.php

Comments