2015-06-12 79 views
1

所以最近我有以下問題:我必須做一個服務器來處理請求,以便在主進程使用這個值時更新一些值。 所以在這裏,服務器處理函數在子進程中,當我需要時我無法停止它。threading.Thread against multiprocessing.Process

爲了測試什麼threading.Threadmultiprocessing.Process之間我的問題的最佳解決方案,我做了這個小程序如下:

import multiprocessing 
import time 
import threading 

class SubProcess(multiprocessing.Process): 

    def __init__(self, source): 
     self.source = source 
     super(SubProcess, self).__init__() 

    def run(self): 
     while 1: 
      time.sleep(1) # Waiting for request... 
      self.source.somevar["anotherkey"].append(5) 
      print "My subprocess : ", id(self.source), id(self.source.somevar), self.source.somevar 

class SubThread(threading.Thread): 

    def __init__(self, source): 
     self.source = source 
     super(SubThread, self).__init__() 

    def run(self): 
     while 1: 
      time.sleep(1) # Waiting for request... 
      self.source.somevar["anotherkey"].append(5) 
      print "My subthread : ", id(self.source), id(self.source.somevar), self.source.somevar 

class Source: 

    def __init__(self): 
     self.somevar = {"akey": "THE key", "anotherkey": [5]} 

    def start_process(self): 
     self.process = SubProcess(self) 
     self.process.start() 

    def stop_process(self): 
     self.process.terminate() 

    def start_thread(self): 
     self.thread = SubThread(self) 
     self.thread.start() 

    def stop_thread(self): 
     # self.thread.stop() # What the hell should i put here 
     pass 

s = Source() 

s.start_process() 
time.sleep(2) 
print "End : ", id(s), id(s.somevar), s.somevar 
s.stop_process() 

s.start_thread() 
time.sleep(2) 
print "End : ", id(s), id(s.somevar), s.somevar 
s.stop_thread() # Obviously, thread never ends... 

所以threading.Thread修改原始s.somevar但我不能阻止它,而multiprocessing.Process不會修改原始s.somevar,但我可以阻止它。

我正在尋找一個解決方案,我可以停止線程(用SIGTERM),並在該線程可以修改使用標準庫原班Source。有沒有解決方法?

回答

1

要殺死線程,你需要在子線程和主線程之間做一些合作。有了您的示例代碼,你可以使用一個threading.Event

class SubThread(threading.Thread): 

    def __init__(self, source): 
     self.source = source 
     self.should_stop = threading.Event() 
     super(SubThread, self).__init__() 

    def run(self): 
     while not self.should_stop.wait(1): 
      #time.sleep(1) # No need to sleep, since we're waiting for 1 second above. 
      self.source.somevar["anotherkey"].append(5) 
      print "My subthread : ", id(self.source), id(self.source.somevar), self.source.somevar 

    def stop(self): 
     """ Call this to abort the thread. """ 
     self.should_stop.set() 

這是不是立即終止,因爲它可以與process.terminate(),因爲你必須竟然打調用should_stop.wait()停止線程之前。

爲了使SubProcess正常工作,您需要使用一個進程安全的共享變量。 multiprocessing模塊爲此提供了multiprocessing.Manager;它允許您在管理器進程中創建共享變量。但是,更新字典的方式實際上有點棘手,因爲要從Manager(請參閱here上的註釋)中獲得的Proxy對象內部的可變值發生一些限制。你必須明確地重新分配更新列表的字典爲正確更新字典:

class SubProcess(multiprocessing.Process): 

    def __init__(self, source): 
     self.source = source 
     super(SubProcess, self).__init__() 

    def run(self): 
     while 1: 
      time.sleep(1) # Waiting for request... 
      # Can't do this with a Manager.dict 
      #self.source.somevar["anotherkey"].append(5) 

      # Do this instead. You'd need to do it with SubThread.run, too. 
      l = self.source.somevar["anotherkey"] 
      l.append(5) 
      self.source.somevar["anotherkey"] = l 
      print "My subprocess : ", id(self.source), id(self.source.somevar), self.source.somevar 

class Source: 

    def __init__(self): 
     self.m = multiprocessing.Manager() 
     # somevar is now process-safe. 
     self.somevar = self.m.dict({"akey": "THE key", "anotherkey": [5]}) 

    # The rest is the same