2010-04-15 36 views
0
運行

比方說,我有一個對象是誰的類定義是這樣的:排隊方法在對象上通過不同的線程在Python

​​

如果這個類實例化一次,但不同的線程中擊中它的run方法(通過一個HTTP請求,單獨處理)傳遞不同的參數,排隊它們的最佳方法是什麼?這可以在類定義本身中完成嗎?

我正在使用XML RPC服務器(單獨的類)。爲了簡單起見,我們可以說它有一個Command類的實例作爲類變量實例化。當Command.run()被兩個單獨的線程命中時,如何確保一個run()方法在下一個啓動之前完成?

我可以這樣做:

while self.busy: 
    time.sleep(1) 
    self.busy = true 
    ... 
    self.busy = false 
    return self.foo 

但是,據我所知,也不會到最久遠的請求優先。

我意識到整個練習聽起來多麼冗餘,因爲我可以同步運行XML-RPC服務器。但是,長話短說,有多個Command實例,我不想阻止一個請求,因爲另一個忙。

我希望這樣做更有意義。

謝謝。

回答

1

這裏有一個比較簡單的辦法(忽略例外,屬性的訪問,特殊方法等):

import Queue 
import threading 

def serialize(q): 
    """runs a serializer on queue q: put [-1]*4 on q to terminate.""" 
    while True: 
    # get output-queue for result, a callable, its args and kwds 
    out_q, tocall, args, kwds = q.get() 
    if out_q == -1: 
     return 
    result = tocall(*args, **kwds) 
    out_q.put(result) 

class WrapCall(object): 
    """Wraps a callable to serialize calls to it.""" 

    def __init__(self, inq, ouq, tocall): 
    self.inq = inq 
    self.ouq = ouq 
    self.tocall = tocall 

    def __call__(self, *a, **k): 
    self.inq.put((self.ouq, self.tocall, a, k)) 
    if self.ouq is None: 
     return None 
    return self.ouq.get() 

class WrapObj(object): 
    """Wraps any object to serialize all calls to its methods.""" 

    def __init__(self, obj): 
    self._o = obj 
    self._q = Queue.Queue() 
    t = threading.Thread(target=serialize, args=(self._q,)) 
    t.setDaemon(True) 
    t.start() 
    self.t = t 

    def __getattr__(self, n): 
    """Wraps methods of self.w into an appropriate WrapCall instance.""" 
    towrap = getattr(self._o, n) 
    if not callable(towrap): 
     raise TypeError('Cannot wrap noncallable attribute %r (type: %s)' 
         % (n, type(towrap))) 
    q = Queue.Queue() 
    return WrapCall(self._q, q, towrap) 

    def WrapperWait(self): 
    """Return only when self.t has served all pending requests.""" 
    q = Queue.Queue() 
    w = WrapCall(self.__q, q, lambda: None) 
    return w() 

有了這個 「串行」,你可以做

myobj = WrapObj(Command()) 

,現在所有通話到myobj的(非特殊)方法是以線程安全的方式序列化的。

對於你的具體情況,只有一個方法的對象,你可以簡化這一點,但這是一個已經簡化版本的東西,我寫和經常使用(支持屬性獲取和設置,特殊方法等等,太複雜了,不值得;完整的版本確實支持捕獲和重新調整包裝器對象方法中引發的異常,優化調用的結果或異常,你不關心,以及一些更多的調整,但不包括屬性和特殊方法的序列化)。

+0

非常酷。這只是我所希望的。 – Ben 2010-04-15 04:32:46

+0

獲取異常拋出: exceptions.AttributeError:'WrapCall'對象沒有屬性'委託' 任何想法? 謝謝, 本 – Ben 2010-04-28 19:28:28

+0

@本,對不起,我只是部分重命名了一個屬性 - 它現在名爲'tocall',** not **'delegate',所以我只是編輯它來修復。 – 2010-04-29 02:31:02

0

這取決於你打算如何消費foo。最簡單的方法是使用Python的queue模塊同步向消費者傳遞值,但假設消費者想要接收每個值。你可能必須更具體才能得到更好的答案。

相關問題