python多处理 - 暂停worker函数,直到queue有另一个要处理的数据

时间:2015-01-03 19:23:43

标签: python queue multiprocessing

我对理解python多处理没什么问题。我写了一个应用程序,巫婆分析下载的网页。我想在具有特定超时的单独进程中获取原始html。我知道我可以在urllib2中设置超时,但在某些情况下使用socks5代理时似乎无法正常工作。 所以,写了一个小类:

class SubprocessManager(Logger):

    def __init__(self, function):
        self.request_queue = Queue()
        self.return_queue = Queue()
        self.worker = function
        self.args = ()
        self.kwargs = {'request_queue': self.request_queue,
                       'return_queue': self.return_queue}
        self._run()

    def _run(self):
        self.subprocess = Process(target=self.worker, args=self.args, kwargs=self.kwargs)
        self.subprocess.start()

    def put_in_queue(self, data):
        self.request_queue.put(data)

    def get_from_queue(self):
        result = None
        try:
            result = self.request_queue.get(timeout=10)
        except Empty:
            self.reset_process()
        return result

    def reset_process(self):
        if self.subprocess.is_alive():
            self.subprocess.terminate()
        self._run()

工人职能:

def subprocess_fetch_www(*args, **kwargs):

    request_queue = kwargs['request_queue']
    return_queue = kwargs['return_queue']
    while True:
        request_data = request_queue.get()
        if request_data:
            return_data = fetch_request(*request_data)
            return_queue.put(return_data)

从输入列表为每个URL调用的函数:

def fetch_html(url, max_retry=cfg.URLLIB_MAX_RETRY, to_xml=False, com_headers=False):

    subprocess = Logger.SUBPROCESS
    args = (url, max_retry, com_headers)
    subprocess.put_in_queue(args)
    result = subprocess.get_from_queue()

    if result and to_xml:
        return html2lxml(result)
    return result

我需要帮助修复我的代码。我希望我的子进程一直在运行,等待request_queue中的作业。我想只在超时的情况下重新创建子进程。一旦处理了request_data并将return_data放入返回队列,Worker就应该暂停执行。

我如何实现这一目标?

编辑:

好吧,如果get_from_queue请求return_queue的结果数据而不是request_queue ...> _>'

,上面的代码似乎按预期工作

1 个答案:

答案 0 :(得分:1)

好的,我想我对你想做的事情有了更好的理解。

看看这段代码。这不是OO,但说明了这个想法。

from multiprocessing import Process, Queue, Pipe
from time import sleep
import random

proc = None
inq = None
outq = None

def createWorker():
  global inq, outq, proc
  inq = Queue()
  outq = Queue()
  proc = Process(target=worker, args=(inq,outq))
  proc.start()

def worker(inq, outq):
  print "Worker started"
  while True:
    url = inq.get()
    secs = random.randint(1,5)
    print "processing", url, " sleeping for", secs
    sleep(secs)
    outq.put(url + " done")

def callWithTimeout(arg):
  global proc, inq, outq
  inq.put(arg)
  result = None
  while result is None:
    try:
      result = outq.get(timeout=4)
    except:
      print "restarting worker process"
      proc.terminate()
      createWorker()
      inq.put(arg)
  return result

def main():
  global proc, inq, outq
  createWorker()

  for arg in ["foo", "bar", "baz", "quux"]:
    res = callWithTimeout(arg)
    print "res =", res

  proc.terminate()

main()

它使用两个队列 - 一个用于向工作进程发送消息,另一个用于接收结果。你也可以使用管道。此外,重新启动工作进程时会创建新队列 - 这是为了避免可能的竞争条件。

编辑:刚刚看到你的编辑 - 看起来是一样的想法。