這裏有一個比較簡單的辦法(忽略例外,屬性的訪問,特殊方法等):
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的(非特殊)方法是以線程安全的方式序列化的。
對於你的具體情況,只有一個方法的對象,你可以簡化這一點,但這是一個已經簡化版本的東西,我寫和經常使用(支持屬性獲取和設置,特殊方法等等,太複雜了,不值得;完整的版本確實支持捕獲和重新調整包裝器對象方法中引發的異常,優化調用的結果或異常,你不關心,以及一些更多的調整,但不包括屬性和特殊方法的序列化)。
非常酷。這只是我所希望的。 – Ben 2010-04-15 04:32:46
獲取異常拋出: exceptions.AttributeError:'WrapCall'對象沒有屬性'委託' 任何想法? 謝謝, 本 – Ben 2010-04-28 19:28:28
@本,對不起,我只是部分重命名了一個屬性 - 它現在名爲'tocall',** not **'delegate',所以我只是編輯它來修復。 – 2010-04-29 02:31:02