2012-11-10 58 views
3

我有一個Bottle應用程序,它使用子進程爲請求執行大部分工作。對於返回單個響應的路由,我會執行類似下面的操作。使用Python瓶,多處理和gevent流連接

@route('/index') 
def index(): 
    worker = getWorker() 
    return worker.doStuff() 

我的一條路線需要是數據流。我找不到一個聰明的方法讓工作人員返回一個響應流。下面的例子與我想要做的相似,只是沒有工人。

@route('/stream') 
def stream(): 
    yield 'START' 
    sleep(3) 
    yield 'MIDDLE' 
    sleep(5) 
    yield 'END' 

我希望能夠做到像下面這樣的東西。由於我不能產生/返回發電機,所以這是不可能的。

@route('/stream') 
def stream(): 
    worker = getWorker() 
    yield worker.doStuff() 
class worker: 
    # Remember, this is run in a subprocess in real life. 
    def doStuff(): 
     yield 'START' 
     sleep(3) 
     yield 'MIDDLE' 
     sleep(5) 
     yield 'END' 

這是一個大型項目,我沒有太多的靈活性,我做事情的方式。我知道有時候最簡單的答案是「你的設計是錯誤的。」在這種情況下,我有一些我無法控制的約束(路由必須是數據流,而且工作必須由子進程完成)。

編輯 我也不能有doStuff()塊。我希望能夠創建類似於我返回並具有工作進程的gevent隊列。現在的問題是,它似乎並不像我可以一起使用gevent.queue和Process。

@route('/stream') 
def index(): 
    body = gevent.queue.Queue() 
    worker = multiprocessing.Process(target=do_stuff, args=body) 
    worker.start() 
    return body() 

def do_stuff(body): 
    while True: 
     gevent.sleep(5) 
     body.put("data") 

回答

0

經過大量的研究和實驗後,我確定gevent隊列不能用於Python多處理。不用這樣做,像redis這樣的東西可以用來讓進程和gevent greenlet進行通信。

@route('/stream') 
def index(): 
    worker = multiprocessing.Process(target=do_stuff) 
    worker.start() 
    yield redis_server.lpop() 

def do_stuff(body): 
    while True: 
     gevent.sleep(5) 
     redis_server.lpush("data") 
1

在你的最後一個例子,worker.doStuff()返回一個生成器,這是迭代。您可以將其退回(將yield更改爲return)。 Bottle接受iterables作爲返回值,只要它們產生字節或unicode字符串。

+0

這是一個簡化的例子。實際的應用程序將會傳輸大量數據。如果我返回一個迭代器,那麼我是否必須首先使用所有數據填充它,而不是流?也許我可以從doStuff()返回一個multiprocessing.Queue,讓工作人員繼續填充它。 –