2010-04-16 3 views
2

Python 2.6을 사용하여 막혔다 고 가정하고 업그레이드 할 수 없습니다 (도움이된다고해도). Queue 클래스를 사용하는 프로그램을 작성했습니다. 제작자는 간단한 디렉토리 목록입니다. 내 소비자 스레드가 대기열에서 파일을 가져 와서 처리합니다. 파일이 이미 처리 된 경우 건너 뜁니다. 처리 된 목록은 모든 스레드가 시작되기 전에 생성되므로 비어 있지 않습니다.Python 2.6의 Queue 클래스 사용

여기에 몇 가지 의사 코드가 있습니다.

import Queue, sys, threading 

processed = [] 

def consumer(): 
    while True: 
     file = dirlist.get(block=True) 
     if file in processed: 
      print "Ignoring %s" % file 
     else: 
      # do stuff here 
     dirlist.task_done() 

dirlist = Queue.Queue() 

for f in os.listdir("/some/dir"): 
    dirlist.put(f) 

max_threads = 8 

for i in range(max_threads): 
    thr = Thread(target=consumer) 
    thr.start() 

dirlist.join() 

내가 갖는 이상한 행동이 스레드가 이미 처리 된 것 파일을 발견 할 경우, 스레드가 밖으로 포장 마차 것입니다 전체 프로그램이 종료 될 때까지 기다립니다. 나는 약간의 테스트를 마쳤으며 첫 번째 7 개의 스레드 (8이 최대라고 가정)를 중단하고 8 번째 스레드는 한 번에 하나의 파일을 처리합니다. 그러나 그렇게함으로써, 응용 프로그램을 스레딩하는 전체 이유를 잃어 가고 있습니다.

내가 잘못하고있는 것입니까, 아니면 Python 2.6의 Queue/threading 클래스의 예상되는 동작입니까?

+1

뭔가 틀린 것이 있어야합니다 - 대기열과 전혀 관련이없는 테스트에 따라 스톨이 어떻게 _ 예상 _ 할 수 있습니까?하지만이 코드의 결함 (스레드가 아닌 데몬, 내장 이름'file'의 남용)이이 코드에 있다고 생각하지 않습니다. - 스레드가 멈추게 만들 수 있다고 생각하지 않습니다! 오히려 처리 된 데이터가 어떻게 처리되고 "..."부분에서 변경됩니까? (주위에 잠금이 없으므로 문제가 될 수 있습니다)? 처리 된 (예 : 파일의 절반을 넣으십시오) 사소한 "..."과 같은 사소한 개체 (예 :'print file')로이 문제를 재현 할 수 있습니까? –

답변

1

이 문제는 이미 처리 된 파일을 찾을 때만 나타납니다. 이는 processed 목록 자체와 관련이있는 것으로 보입니다. 간단한 자물쇠를 실행 해 보셨습니까? 예를 들면 다음과 같습니다.

processed = [] 
processed_lock = threading.Lock() 

def consumer(): 
    while True: 
     with processed_lock.acquire(): 
      fileInList = file in processed 
     if fileInList: 
      # ... et cetera 

스레딩은 발생하지 않아도 가장 이상한 버그를 유발하는 경향이 있습니다. 공유 변수에 잠금을 사용하는 것은 스레드가 교착 상태를 일으킬 수있는 일종의 경쟁 상태로 끝나지 않도록하는 첫 번째 단계입니다. 물론


, 당신이 # do stuff here에서하고있는 것은 CPU를 많이 사용하는 경우, 다음 파이썬은 인해 글로벌 통역 잠금에, 어쨌든 한 번에 하나 개의 스레드에서 코드를 실행합니다. 이 경우 multiprocessing 모듈로 전환 할 수 있습니다. threading과 매우 유사하지만 공유 변수를 다른 솔루션으로 바꿔야합니다 (자세한 내용은 here 참조).

+0

나는 처리 목록에 자물쇠를 넣는 것을 생각하지 않았습니다. 이제는 생각해 보았습니다. 그리고 멀티 프로세싱 모듈을 사용하도록 권장 해 주셔서 감사합니다. – Pat

2

코드를 실행했지만 설명하는 동작을 보지 못했습니다. 그러나 프로그램은 종료되지 않습니다.

try: 
     file = dirlist.get(True, 1) 
    except Queue.Empty: 
     return 

현재 실행되는 스레드 알고 싶다면

, 당신은 thread 모듈 및 인쇄 thread.get_ident()를 가져올 수 있습니다 다음과 같이 나는 .get() 전화를 변경하는 것이 좋습니다.

은 내가 .get() 후 다음 줄 추가 :

print file, thread.get_ident() 

을 다음과 같은 출력을 가지고 : 스레드가 동시에 표준 출력에 기록되기 때문에

bin 7116328 
cygdrive 7116328 
cygwin.bat 7149424 
cygwin.ico 7116328 
dev etc7598568 
7149424 
fix 7331000 
home 7116328lib 
7598568sbin 
7149424Thumbs.db 
7331000 
tmp 7107008 
usr 7116328 
var 7598568proc 
7441800 

출력은 지저분한입니다. 다양한 스레드 식별자는 모든 스레드가 실행 중임을 확인합니다.

아마도 실제 코드 나 테스트 방법론에는 문제가 있지만 게시 한 코드에는 문제가 있습니까?

+0

아, 왜 내가 프로그램을 계속 죽여야 만하는지 설명합니다. 팁 고마워. – Pat

+0

@voipme 감사합니다. 투표가 더 좋습니다. :-) –