2011-09-02 6 views
0

cPython으로 스레딩하는 동안 동기화 문제가 있습니다. 나는 두 개의 파일을 가지고 있으며, 그것들을 파싱하고 원하는 결과를 리턴한다. 그러나 아래의 코드는 이상하게 작동하고 두 번 대신 세 번을 반환합니다. 내가 대기열에 넣은 순서대로 반환하지 않습니다. 여기 코드는 다음과 같습니다파이썬 멀티 스레딩 동기화

import Queue 
import threading 
from HtmlDoc import Document 

OUT_LIST = [] 

class Threader(threading.Thread): 
    """ 
    Start threading 
    """ 
    def __init__(self, queue, out_queue): 
     threading.Thread.__init__(self) 
     self.queue = queue 
     self.out_queue = out_queue 


    def run(self): 
     while True: 
      if self.queue.qsize() == 0: break 

      path, host = self.queue.get() 

      f = open(path, "r") 
      source = f.read() 
      f.close() 

      self.out_queue.put((source, host))   
      self.queue.task_done() 



class Processor(threading.Thread): 
    """ 
    Process threading 
    """ 
    def __init__(self, out_queue): 
     self.out_queue = out_queue 
     self.l_first = [] 
     self.f_append = self.l_first.append 
     self.l_second = [] 
     self.s_append = self.l_second.append 
     threading.Thread.__init__(self) 


    def first(self, doc): 
     # some code to to retrieve the text desired, this works 100% I tested it manually 

    def second(self, doc): 
     # some code to to retrieve the text desired, this works 100% I tested it manually 

    def run(self): 
     while True: 
      if self.out_queue.qsize() == 0: break 

      doc, host = self.out_queue.get() 

      if host == "first": 
       self.first(doc) 
      elif host == "second": 
       self.second(doc) 

      OUT_LIST.extend(self.l_first + self.l_second) 

      self.out_queue.task_done() 


def main(): 

    queue = Queue.Queue() 
    out_queue = Queue.Queue() 

    queue.put(("...first.html", "first")) 
    queue.put(("...second.html", "second")) 

    qsize = queue.qsize() 

    for i in range(qsize): 
     t = Threader(queue, out_queue) 
     t.setDaemon(True) 
     t.start() 

    for i in range(qsize): 
     dt = Processor(out_queue) 
     dt.setDaemon(True) 
     dt.start() 

    queue.join() 
    out_queue.join() 

    print '<br />'.join(OUT_LIST) 

main() 

을 지금, 나는 인쇄 할 때, 나는 "두 번째"의 "첫 번째"모든 제 1 및 컨텐츠의 내용을 인쇄하고 싶습니다. 누구든지 나를 도울 수 있습니까?

참고 : 실제로는 한 번에 10 개 이상의 장소에 연결하고 결과를 검색해야하므로 실제로 스레딩하고 있습니다. 스레딩이 그러한 작업을 수행하는 가장 적절한 방법이라고 생각합니다.

답변

2

실제로는 한 번에 10 개 이상의 장소에 연결하고 그 결과를 검색해야하므로 실제로 스레딩하고 있습니다. 스레드를 사용하는 것이 이러한 작업을 수행하는 가장 적절한 방법이라고 생각합니다.

스레딩은 실제로 여러 동시 연결을 관리하는 가장 오류가 발생하기 쉬운 방법 중 하나입니다. 더욱 강력하고 디버그 가능한 접근 방식은 Twisted과 같이 구현 된 이벤트 기반 비동기 네트워킹을 사용하는 것입니다. 이 모델을 사용하는 데 관심이 있으시면 this introduction을 확인하시기 바랍니다.

1

스레딩이 (IMO 일부 이벤트/선택 메커니즘이 더 좋음) 이렇게하는 가장 좋은 방법이라고 생각하지만 코드에 문제가있을 수 있습니다. 변수 t와 dt에 있어야합니다. 사이클에 할당이 있고 개체 인스턴스는 어느 위치 에나 저장되므로 스레드/프로세서의 새 인스턴스가 각주기의 끝에서 삭제 될 수 있습니다.

이 코드의 정확한 출력을 보여 주면 더 명확하게 나타납니다.

0

1) 작업 완료 순서를 제어 할 수 없습니다. 실행 시간에 따라 다르므로 작업 결과를 원하는대로 반환하려면 job_results : { 'first': None, 'second': None}과 같은 작업 개체를 사용하여 전역 사전을 만들고 여기에 결과를 저장하십시오. 원하는 데이터를 가져올 수 있습니다.

2) self.firstself.second 각 처리 문서 후 취소해야 질서, 다른 사람이 당신은 하위 프로세스 모듈과 멀티 프로세싱을 사용하고, 예를 들어 CSV 파일에 대한 모든 결과 데이터를 입력 할 수 있습니다)

3 OUT_LIST

에 중복이있을 것이다 원하는대로 정렬합니다.

+0

나는 동기화 문제가있는 과도한 작업과 여러 서버에서 스크립트를 실행해야 할 때 더 높은 parallism 수준을 가질 수 있기 때문에 멀티 스레딩을 통해 다중 프로세스를 우선시합니다. – varela

+0

I/O 바운드 스레드는 GIL 및 컨텍스트 스위칭에 훨씬 덜 종속적입니다. 스레드는 프로세스보다 리소스를 덜 소비하며,이 경우에는 문제가 없습니다. – Martin