Python Threading

|

threading

Object Description
Thread thread 객체
Lock 기본 lock 객체
RLock 재진입 가능한 lock 객체
Condition 다른 쓰레드의 신호를 기다리는 condition 변수 객체
Event 컨디션의 일반화 버젼
Semaphore 세마포어
BoundedSemaphore 초기값 이상으로 증가할 수 없는 세마포어
Timer 지정된 시간동안 대기하고 실행되는 thread
Barrier thread가 계속 진행되려면 지정된 숫자의 thread가 해당 지점까지 도달해야함

Thread class

method/attribute Description
daemon daemon thread인지..
__init__ 초기화
start() thread 실행
run() thread의 기능을 담당
join(timeout=None) thread가 종료될 때까지 대기한다

예제

함수를 넘김

import threading
from time import sleep, ctime

loops = [3, 1]

def loop(nloop, nsec):
    print('start loop {} at: {}'.format(nloop, ctime()))
    sleep(nsec)
    print('loop {} at: {}'.format(nloop, ctime()))


def test() :
    print('starting at: {}'.format(ctime()))
    threads = []
    nloops = range(len(loops))

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

    # thread들을 모두 실행시킨다.
    for i in nloops:
        threads[i].start()

    # thread들을 모두 join
    for i in nloops:
        threads[i].join()

    print('all Done at: {}'.format(ctime()))

if  __name__ == '__main__' : 
   test()

결과 :

starting at: Fri Sep  1 17:06:49 2017
start loop 0 at: Fri Sep  1 17:06:49 2017
start loop 1 at: Fri Sep  1 17:06:49 2017
loop 1 at: Fri Sep  1 17:06:50 2017
loop 0 at: Fri Sep  1 17:06:52 2017
all Done at: Fri Sep  1 17:06:52 2017

상속을 통해서

import threading
from time import sleep, ctime

loops = [3,1]

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

    def run (self):
        print('start loop: {} at: {}'.format(self.args[0], ctime()))
        sleep(self.args[1])
        print('done loop: {} at: {}'.format(self.args[0], ctime()))


def test() :
    print('starting at: {}'.format(ctime()))
    threads = []
    nloops = range(len(loops))

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

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

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

    print('all Done at: {}'.format(ctime()))

if  __name__ == '__main__' : 
   test()

결과 :

starting at: Fri Sep  1 17:14:36 2017
start loop: 0 at: Fri Sep  1 17:14:36 2017
start loop: 1 at: Fri Sep  1 17:14:36 2017
done loop: 1 at: Fri Sep  1 17:14:37 2017
done loop: 0 at: Fri Sep  1 17:14:39 2017
all Done at: Fri Sep  1 17:14:39 2017

Condition

Contition 객체를 사용하는 예제를 적는다. 여기서 with statement를 쓰는 것을 볼 수 있는데…

with some_lock:
    # do something...

some_lock.acquire()
try:
    # do something...
finally:
    some_lock.release()

과 동치라고 한다. python 3부터 그런가보다..

밑의 예제는 하나씩 notify를 하는 것을 만들어보았고 notify_all()로 한번에 끝낼 수도 있다.

import threading
import time
import logging

logging.basicConfig(level=logging.DEBUG,
                    format='(%(threadName)-9s) %(message)s')

def consumer(cv):
    logging.debug('start')
    with cv:
        logging.debug('waiting')
        cv.wait()
        logging.debug('consumed the resource')

def producer(cv):
    logging.debug('start')
    with cv:
        logging.debug('produce a resource')
        cv.notify()
    
    logging.debug('sleep 4 seconds')
    time.sleep(4)
    with cv:
        logging.debug('produce a resource')
        cv.notify()

if __name__ == '__main__':
    condition = threading.Condition()
    cs1 = threading.Thread(name='consumer1', target=consumer, args=(condition,))
    cs2 = threading.Thread(name='consumer2', target=consumer, args=(condition,))

    pd  = threading.Thread(name='producer',  target=producer, args=(condition,))

    cs1.start()
    cs2.start()
    time.sleep(1)
    pd.start()


결과 :

(consumer1) start
(consumer1) waiting
(consumer2) start
(consumer2) waiting
(producer ) start
(producer ) produce a resource
(producer ) sleep 4 seconds
(consumer1) consumed the resource
(producer ) produce a resource
(consumer2) consumed the resource