目标:从redis生成一些greenlet worker处理数据pop(从redis弹出然后放入队列)
RUNNING ENV:ubuntu 12.04 PYTHON VER:2.7 GEVENT VER:1.0 RC2 REDIS VER:2.6.5 REDIS-PY VER:2.7.1
from gevent import monkey; monkey.patch_all()
import gevent
from gevent.pool import Group
from gevent.queue import JoinableQueue
import redis
tasks = JoinableQueue()
task_group = Group()
def crawler():
while True:
if not tasks.empty():
print tasks.get()
gevent.sleep()
task_group.spawn(crawler)
redis_client = redis.Redis()
data = redis_client.lpop('test') #<----------Block here
tasks.put(data)
尝试从redis中弹出数据,但是它被阻止了......没有异常引发......只是冻结 并删除spawn方法,它会工作.. 我感到困惑发生了什么,请帮助! 你好!
答案 0 :(得分:10)
gevent提供合作轻量级进程(而不是线程)。结果是当你在某个地方有一个无限循环并且调度程序永远不会重新进入时,程序将阻止占用100%的CPU内核。
在您的示例中,问题是您定义了爬网程序循环的方式。显然,当任务为空时,你有一个无限循环。并且因为gevent.sleep调用(将执行必要的yield操作)仅在任务不为空时调用,这意味着调度程序永远不会被重新输入。
似乎阻止了lpop命令,因为Redis客户端延迟了连接。事件顺序如下:
如果你把gevent.sleep()放在循环本身(在if之后),它会更好地工作,但它仍然是一种实现dequeuer的低效方法。这样的事情会好得多:
def crawler():
while True:
x = tasks.get()
try:
print "Crawler: ",x
finally:
tasks.task_done()
get()调用阻塞了worker,因此当队列为空时,它将避免worker和scheduler之间的乒乓游戏。