我正在编写一个服务器程序,其中包含一个生产者和多个消费者, 令我困惑的只是生产者放入队列的第一个任务 消耗,然后排队的任务不再被消耗,他们仍然存在 在队列中永远。
from multiprocessing import Process, Queue, cpu_count
from http import httpserv
import time
def work(queue):
while True:
task = queue.get()
if task is None:
break
time.sleep(5)
print "task done:", task
queue.put(None)
class Manager:
def __init__(self):
self.queue = Queue()
self.NUMBER_OF_PROCESSES = cpu_count()
def start(self):
self.workers = [Process(target=work, args=(self.queue,))
for i in xrange(self.NUMBER_OF_PROCESSES)]
for w in self.workers:
w.start()
httpserv(self.queue)
def stop(self):
self.queue.put(None)
for i in range(self.NUMBER_OF_PROCESSES):
self.workers[i].join()
queue.close()
Manager().start()
生产者是一个HTTP服务器,一旦接收就将任务放入队列中 来自用户的请求。似乎消费者流程仍然存在 当队列中有新任务时被阻止,这很奇怪。
P.S。另外两个与上述无关的问题,我不确定是否 最好将HTTP服务器放在除主服务器之外的其他进程中 进程,如果是,我怎么能让主进程继续运行 儿童过程结束。第二个问题,什么是最好的方法来阻止 HTTP服务器优雅吗?
编辑:添加生产者代码,它只是一个简单的python wsgi服务器:
import fapws._evwsgi as evwsgi
from fapws import base
def httpserv(queue):
evwsgi.start("0.0.0.0", 8080)
evwsgi.set_base_module(base)
def request_1(environ, start_response):
start_response('200 OK', [('Content-Type','text/html')])
queue.put('task_1')
return ["request 1!"]
def request_2(environ, start_response):
start_response('200 OK', [('Content-Type','text/html')])
queue.put('task_2')
return ["request 2!!"]
evwsgi.wsgi_cb(("/request_1", request_1))
evwsgi.wsgi_cb(("/request_2", request_2))
evwsgi.run()
答案 0 :(得分:10)
我认为Web服务器部分肯定存在问题,因为这非常有效:
from multiprocessing import Process, Queue, cpu_count
import random
import time
def serve(queue):
works = ["task_1", "task_2"]
while True:
time.sleep(0.01)
queue.put(random.choice(works))
def work(id, queue):
while True:
task = queue.get()
if task is None:
break
time.sleep(0.05)
print "%d task:" % id, task
queue.put(None)
class Manager:
def __init__(self):
self.queue = Queue()
self.NUMBER_OF_PROCESSES = cpu_count()
def start(self):
print "starting %d workers" % self.NUMBER_OF_PROCESSES
self.workers = [Process(target=work, args=(i, self.queue,))
for i in xrange(self.NUMBER_OF_PROCESSES)]
for w in self.workers:
w.start()
serve(self.queue)
def stop(self):
self.queue.put(None)
for i in range(self.NUMBER_OF_PROCESS):
self.workers[i].join()
self.queue.close()
Manager().start()
示例输出:
starting 2 workers
0 task: task_1
1 task: task_2
0 task: task_2
1 task: task_1
0 task: task_1
答案 1 :(得分:4)
“第二个问题,优雅地停止HTTP服务器的最佳方法是什么?”
这很难。
进程间通信有两种选择:
带外控制。服务器有另一种通信机制。另一个套接字,Unix信号或其他东西。其他东西可能是服务器本地目录中的“stop-now”文件。看起来很奇怪,但它确实运行良好,并且比引入选择循环来监听多个套接字或信号处理程序以捕获Unis信号更简单。
“stop-now”文件易于实现。 evwsgi.run()
循环仅在每次请求后检查此文件。要使服务器停止,您需要创建文件,执行/control
请求(这将获得500错误或其他内容,这并不重要),服务器应该停止运行。请记住删除stop-now文件,否则服务器将不会重新启动。
带内控制。服务器有另一个URL(/stop
),它将停止它。从表面上看,这似乎是一场安全噩梦,但它完全取决于该服务器的使用位置和方式。由于它似乎是一个围绕内部请求队列的简单包装器,因此这个额外的URL运行良好。
为了完成这项工作,您需要编写自己的evwsgi.run()
版本,可以通过设置某个变量以终止循环来终止。
修改强>
您可能不想终止服务器,因为您不知道它的工作线程的状态。您需要向服务器发出信号,然后您必须等到它正常完成。
如果您想强制终止服务器,则os.kill()
(或multiprocessing.terminate
)将起作用。当然,除了你不知道子线程在做什么之外。
答案 2 :(得分:1)