2014-02-13 1 views
3

다중 스레드 응용 프로그램을 파이썬으로 개발 중입니다. 특히이 응용 프로그램에서 스레드는 하나 이상의 스레드에 통보해야하는 이벤트를 생성 할 수 있어야합니다. 이벤트 통지를 수신 한 스레드는 실행을 인터럽트하고 특정 기능을 실행해야합니다. 이 서비스 기능이 끝나면 이벤트가 생성되기 전에 무엇을하고 있었는지 되돌아 가야합니다.파이썬 : 다른 스레드에 의해 통지 된 이벤트를 관리하는 스레드

이렇게하기 위해 일종의 게시/구독 모듈을 사용하려고했습니다. 매우 사용하기 쉬운 하나를 찾았습니다 : PyPubSub. here은 사용 방법에 대한 매우 간단한 예입니다.

그건 그렇고, 내가 이것을 사용하기 시작했을 때, 내가 찾던 것을 깨달았지만 프로세스 인으로 작업 할 때만 깨달았다. 스레드가 더 많은 경우 특정 루틴을 실행하기 위해 전체 프로세스 (즉, 모든 스레드)를 일시 중단합니다. 이것은 내가 실제로 찾고 있었던 행동이 아닙니다. 불행히도 멀티 스레드에서 멀티 프로세스로 응용 프로그램을 변경할 수 없습니다.

멀티 스레드 응용 프로그램에서 수행하려고하는 작업을 수행하는 데 도움이되는 모듈을 알고 있습니까? 감사.

+0

"전체 프로세스 (즉, 모든 스레드)가 일시 중단됩니다."- GIL 또는 "정지"를 유발하는 다른 것을 언급하고 있습니까? – shx2

답변

3

GIL이 그림의 일부가 아니기 때문에 다중 처리 모듈을 제외하고는 파이썬에서 진정한 동시성이 없습니다.

원하는 작업은 이벤트 대기열을 확인하고 적절하게 디스패치하는 이벤트 루프가 필요합니다. Pububsub 가능성이 귀하의 인생을 더 쉽게 만들 수 있지만 당신이 원하는 pubsub의 저자로서 나는 과분할지도 모릅니다 : :) 다중 프로세스의 완벽한 통합이 mp 모듈에 의해 어떻게 제공되는지 감안할 때 실제로 사용하지 않는 이유가 있습니까? 병행 성이 정말로 필요한 경우?

모든 스레드에서 하나 이상의 스레드로 이벤트를 이동하려는 사실은 스레드가 게시 할 수있는 공유 게시 대기열 (어떤 이벤트 유형 및 이벤트 데이터를 나타내는 데이터)을 사용할 수 있음을 나타냅니다. 또한 각 스레드에 대해 메시지 대기열을 갖게됩니다. 공유 게시 대기열에 게시하는 스레드, 기본 프로세스 이벤트 루프는 게시 대기열을 확인하고 이벤트를 개별 스레드 메시지 대기열에 적절하게 복사합니다. 각 스레드는 큐를 정기적으로 확인하고 프로세스 된 이벤트를 제거해야합니다. 각 스레드는 특정 이벤트에 대한 기본 프로세스를 구독 할 수 있습니다.

가 여기에 서로 메시지를주고 3 개 보조 스레드의 예입니다

from multiprocessing import Process, Queue, Lock 
from Queue import Empty as QueueEmpty 
from random import randint 


def log(lock, threadId, msg): 
    lock.acquire() 
    print 'Thread', threadId, ':', msg 
    lock.release() 


def auxThread(id, lock, sendQueue, recvQueue, genType): 
    ## Read from the queue 
    log(lock, id, 'starting') 
    while True: 
     # send a message (once in a while!) 
     if randint(1,10) > 7: 
      event = dict(type = genType, fromId = id, val = randint(1, 10)) 
      log(lock, id, 'putting message type "%(type)s" = %(val)s' % event) 
      sendQueue.put(event) 

     # block until we get a message: 
     maxWait = 1 # second 
     try: 
      msg = recvQueue.get(False, maxWait) 
      log(lock, id, 'got message type "%(type)s" = %(val)s from thread %(fromId)s' % msg) 
      if (msg['val'] == 'DONE'): 
       break 
     except QueueEmpty: 
      pass 

    log(lock, id, 'done') 


def createThread(id, lock, postOffice, genType): 
    messagesForAux = Queue() 
    args = (id, lock, postOffice, messagesForAux, genType) 
    auxProc = Process(target=auxThread, args=args) 
    auxProc.daemon = True 
    return dict(q=messagesForAux, p=auxProc, id=id) 


def mainThread(): 
    postOffice = Queue() # where all threads post their messages 
    lock = Lock() # so print can be synchronized 

    # setup threads: 
    msgThreads = [ 
     createThread(1, lock, postOffice, 'heartbeat'), 
     createThread(2, lock, postOffice, 'new_socket'), 
     createThread(3, lock, postOffice, 'keypress'), 
    ] 

    # identify which threads listen for which messages 
    dispatch = dict(
     heartbeat = (2,), 
     keypress = (1,), 
     new_socket = (3,), 
    ) 

    # start all threads 
    for th in msgThreads: 
     th['p'].start() 

    # process messages 
    count = 0 
    while True: 
     try: 
      maxWait = 1 # second 
      msg = postOffice.get(False, maxWait) 
      for threadId in dispatch[msg['type']]: 
       thObj = msgThreads[threadId - 1] 
       thObj['q'].put(msg) 
      count += 1 
      if count > 20: 
       break 

     except QueueEmpty: 
      pass 

    log(lock, 0, "Main thread sending exit signal to aux threads") 
    for th in msgThreads: 
     th['q'].put(dict(type='command', val='DONE', fromId=0)) 

    for th in msgThreads: 
     th['p'].join() 
     log(lock, th['id'], 'joined main') 
    log(lock, 0, "DONE") 


if __name__ == '__main__': 
    mainThread() 

당신은 완전히 맞아 pypubsub 기능이 설명이 주 유사성하지만 pypubsub의 작은 부분 만 사용하는 것 즉, 노력의 복잡성 대부분이 두 가지 유형의 대기열이라고 생각합니다. pypubsub는이 문제에 대해 많은 도움이됩니다. mp 모듈을 사용하여 큐 시스템을 작동 시키면 (필자의 예제에 따라), 필자 자신의 이벤트가 아닌 pypubsub를 가져 와서 메시지를 게시/대기시킬 수 있습니다.

+0

사실 내 의도는 내 스레드가 뭔가를하고 그들의 활동을하는 동안 그들을 방해하는 것이 었습니다. 그래서 저는 이벤트 루프에 대해 정말로 생각하지 않았습니다. 하지만 어쩌면 내 프로그램의 구조를 약간 변경하면 효과가있을 수 있습니다. 그리고 ... 어떻게 이벤트 루프를 만들겠습니까? 조건이있는 while 루프 새로운 이벤트가 있는지 확인하는 True? 어쨌든 메시지에 쓴 내용을 명확히하기 위해 게시 할 수있는 코드는 무엇이든지 좋습니다. – Cell

+0

나는 비 - 메인 쓰레드를 방해하는 어떤 방법도 모른다. (심지어 시그널 모듈은 메인 쓰레드에만 신호를 보내고 유닉스에서만 작동한다.) 나는 실천 사례, hth로 확장했다. – Schollii

관련 문제