2012-12-29 30 views
5

目標:產卵數greenlet工人處理從Redis的數據彈出(從Redis的流行,然後放入隊列)GEVENT塊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的數據,但它blocked..and也不例外提出...只是凍結 和刪除產卵法,它會工作.. 我覺得混淆什麼hap pened,plz幫助! thk u!

回答

9

gevent提供合作輕量級進程(不是線程)。其結果是當你在某個地方有一個無限循環並且調度器從不重新進入時,程序將阻止100%的CPU核心。

在您的示例中,問題在於您定義了爬網程序循環的方式。顯然,當任務是空的時候你有一個無限循環。而且因爲gevent.sleep調用(這將執行必要的yield操作)僅在任務不爲空時調用,這意味着調度程序永遠不會重新輸入。

它似乎阻止了lpop命令,因爲連接被Redis客戶端延遲。事件的順序如下:

  • 任務組被產生;但沒有預定greenlet
  • redis_client是內置的,但由於實際連接被延遲,它不會生成I/O
  • lpop被調用;這次連接確實是需要的,因爲Redis客戶端必須等待連接並回復lpop;因此,它產生的調度
  • 調度激活一個履帶工人
  • 無限循環,因爲任務隊列仍然是空

如果你把循環本身的gevent.sleep()(後如果),它會工作得更好,但它仍然是一個低效率的方式來實施出uer者。這樣的事情會好得多:

def crawler(): 
    while True: 
     x = tasks.get() 
     try: 
      print "Crawler: ",x 
     finally: 
      tasks.task_done() 

的get()調用阻止工人,所以它會避免工人和調度之間的乒乓遊戲的同時隊列爲空。

+0

這是爲什麼downvoted? – schlamar

+0

我不知道,但我仍然支持我的答案;-) –