В целом это главным образом то же кроме того, чтобы быть явным о мониторе объекта, это используется по сравнению с неявным этот объект. Одна оборотная сторона синхронизированных методов, что я думаю, иногда пропускается, то, что в использовании "этой" ссылки для синхронизации на Вас оставляют открытыми возможность внешних объектов, соединяющих тот же объект. Это может быть очень тонкой ошибкой при столкновении с нею. Синхронизация на внутреннем явном Объекте или другом существующем поле может избежать этой проблемы, полностью инкапсулируя синхронизацию.
Этот "код" Слушателей Генератора Python позволяет Вам иметь многих слушателей на единственном генераторе, как os.walk
, и даже сделать, чтобы кто-то "вмешался" позже.
определение walkme (): os.walk ('/home')
m1 = Muxer(walkme) m2 = Muxer(walkme)
затем m1 и m2 может работать в потоках даже и обработать на их досуге.
См.: https://gist.github.com/earonesty/cafa4626a2def6766acf5098331157b3
import queue
from threading import Lock
from collections import namedtuple
class Muxer():
Entry = namedtuple('Entry', 'genref listeners, lock')
already = {}
top_lock = Lock()
def __init__(self, func, restart=False):
self.restart = restart
self.func = func
self.queue = queue.Queue()
with self.top_lock:
if func not in self.already:
self.already[func] = self.Entry([func()], [], Lock())
ent = self.already[func]
self.genref = ent.genref
self.lock = ent.lock
self.listeners = ent.listeners
self.listeners.append(self)
def __iter__(self):
return self
def __next__(self):
try:
e = self.queue.get_nowait()
except queue.Empty:
with self.lock:
try:
e = self.queue.get_nowait()
except queue.Empty:
try:
e = next(self.genref[0])
for other in self.listeners:
if not other is self:
other.queue.put(e)
except StopIteration:
if self.restart:
self.genref[0] = self.func()
raise
return e
def __del__(self):
with self.top_lock:
try:
self.listeners.remove(self)
except ValueError:
pass
if not self.listeners and self.func in self.already:
del self.already[self.func]