2015-06-12 48 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