Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/logging/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python Gevent共享队列(侦听器进程)_Python_Logging_Queue_Gevent - Fatal编程技术网

Python Gevent共享队列(侦听器进程)

Python Gevent共享队列(侦听器进程),python,logging,queue,gevent,Python,Logging,Queue,Gevent,我正在尝试使用一些代码,以便使用gevent实现登录到多线程程序。我想做的是设置自定义日志处理程序,将日志事件放入队列中,同时侦听器进程持续监视新的日志事件以进行适当处理。我过去曾使用多处理来实现这一点,但从未使用Gevent 我遇到了一个问题,程序陷入无限循环(侦听器进程),不允许其他线程“工作” 理想情况下,在工作进程完成后,我可以将任意值传递给侦听器进程,让它中断循环,然后将所有进程连接在一起。以下是我目前掌握的情况: import gevent from gevent.pool impo

我正在尝试使用一些代码,以便使用gevent实现登录到多线程程序。我想做的是设置自定义日志处理程序,将日志事件放入队列中,同时侦听器进程持续监视新的日志事件以进行适当处理。我过去曾使用多处理来实现这一点,但从未使用Gevent

我遇到了一个问题,程序陷入无限循环(侦听器进程),不允许其他线程“工作”

理想情况下,在工作进程完成后,我可以将任意值传递给侦听器进程,让它中断循环,然后将所有进程连接在一起。以下是我目前掌握的情况:

import gevent
from gevent.pool import Pool
import Queue
import random
import time

def listener(q):
    while True:
        if not q.empty():
            num = q.get()
            print "The number is: %s" % num
            if num <= 100:
                print q.get()
            # got passed 101, break out
            else:
                break
        else:
            continue
def worker(pid,q):
    if pid == 0:
        listener(q)
    else:
        gevent.sleep(random.randint(0,2)*0.001)
        num = random.randint(1,100)
        q.put(num)

def main():
    q = Queue.Queue()
    all_threads = []
    all_threads = [gevent.spawn(worker, pid,q) for pid in xrange(10)]
    gevent.wait(all_threads[1:])
    q.put(101)
    gevent.joinall(all_threads)

if __name__ == '__main__':
    main()
导入gevent
从gevent.pool导入池
导入队列
随机输入
导入时间
def侦听器(q):
尽管如此:
如果不是q.empty():
num=q.get()
打印“号码为:%s”%num

如果num则第一个问题是,如果队列最初为空,则侦听器永远不会让步。您生成的第一个任务是侦听器。当它开始时,有一个
,而True:
,q将是空的,因此您转到else分支,它只是继续,循环回到while循环的开始,然后q仍然是空的。因此,您只需坐在第一个线程中,不断检查q是否为空

这里的关键是gevent不使用“本机”线程或进程。与“真实”线程不同的是,gevent使用“greenlets”,它要求您对另一个任务进行“屈服控制”,而“真实”线程可以在任何时候通过幕后的东西(比如您的操作系统调度程序)切换到“真实”线程。gevent认为任何东西都会阻塞,例如从网络、磁盘读取,或者使用阻塞gevent操作之一

一个粗略的修复方法是在
pid==9而不是0时启动侦听器。通过使其最后生成,q中将有项目,并且它将进入主if分支。缺点是这并不能解决逻辑问题,所以当队列第一次为空时,您将再次陷入无限循环

更正确的修复方法是放置
gevent.sleep()
,而不是
continue
。睡眠是一个阻塞操作,因此您的其他任务将有机会运行。在没有参数的情况下,它不会等待任何时间,但仍然让gevent有机会在准备运行时决定切换到另一个任务。这仍然不是很有效,但是,如果队列是空的,它将花费大量无意义的时间反复检查,并要求尽快重新运行。睡眠时间超过默认值0将更有效率,但会延迟处理日志消息

但是,您可以利用这样一个事实,即gevent的许多类型(如Queue)都可以以更Pythonic的方式使用,从而使代码更简单、更容易理解,也更高效

import gevent
from gevent.queue import Queue

def listener(q):
    for msg in q:
        print "the number is %d" % msg

def worker(pid,q):
    gevent.sleep(random.randint(0,2)*0.001)
    num = random.randint(1,100)
    q.put(num)

def main():
    q = Queue()
    listener_task = gevent.spawn(listener, q)
    worker_tasks = [gevent.spawn(worker, pid, q) for pid in xrange(1, 10)]
    gevent.wait(worker_tasks)
    q.put(StopIteration)
    gevent.join(listener_task)
这里,
Queue
可以作为
for
循环中的迭代器。只要有消息,它就会获取一个项目,运行循环,然后等待另一个项目。如果没有项目,它将只是阻塞并挂起,直到下一个项目到达。但是,由于它会阻塞,gevent将切换到要运行的其他任务之一,从而避免了示例代码中的无限循环问题

由于此版本使用
队列
作为for循环迭代器,因此还可以自动在队列中添加一个很好的sentinel值,以使侦听器任务退出。如果for循环从其迭代器中获得
StopIteration
,它将干净地退出。因此,当从q读取的for循环从q获取
StopIteration
时,它退出,然后函数退出,生成的任务完成