Как клонировать объект генератора Python ?

В целом это главным образом то же кроме того, чтобы быть явным о мониторе объекта, это используется по сравнению с неявным этот объект. Одна оборотная сторона синхронизированных методов, что я думаю, иногда пропускается, то, что в использовании "этой" ссылки для синхронизации на Вас оставляют открытыми возможность внешних объектов, соединяющих тот же объект. Это может быть очень тонкой ошибкой при столкновении с нею. Синхронизация на внутреннем явном Объекте или другом существующем поле может избежать этой проблемы, полностью инкапсулируя синхронизацию.

50
задан Zero Piraeus 3 February 2015 в 08:33
поделиться

1 ответ

Этот "код" Слушателей Генератора 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]
0
ответ дан 7 November 2019 в 10:55
поделиться
Другие вопросы по тегам:

Похожие вопросы: