Неленивое создание экземпляра с Pyro4 и instance_mode='single'

Моя цель — предоставить веб-фреймворку доступ к демону Pyro, который выполняет трудоемкие задачи при первой загрузке. До сих пор мне удавалось хранить в памяти (вне веб-приложения) один экземпляр класса, который берет на себя трудоемкую загрузку при его инициализации. Я также могу запросить его с помощью своего веб-приложения. Код для демона:

Pyro4.expose
@Pyro4.behavior(instance_mode='single')
class Store(object):

    def __init__(self):
        self._store = ... # the expensive loading

    def query_store(self, query):
        return ... # Useful query tool to expose to the web framework.
                   # Not time consuming, provided self._store is
                   # loaded.

with Pyro4.Daemon() as daemon:
    uri = daemon.register(Thing)
    with Pyro4.locateNS() as ns:
        ns.register('thing', uri)
    daemon.requestLoop()

Проблема, с которой я сталкиваюсь, заключается в том, что, хотя создается один экземпляр, он создается только при первом прокси-запросе из веб-приложения. Это нормальное поведение согласно документу. , но не то, что я хочу, так как первый запрос все еще медленный из-за инициализации Thing.

Как я могу убедиться, что экземпляр уже создан, как только запущен демон?

Я думал создать прокси-экземпляр Thing в коде демона, но это сложно, потому что цикл событий должен быть запущен.

ИЗМЕНИТЬ

Оказывается, daemon.register() может принимать либо класс, либо объект, что может быть решением. Однако это не рекомендуется в документе (ссылка выше), и эта функция, по-видимому, существует только для обратной совместимости.


person mimo    schedule 01.02.2018    source источник


Ответы (1)


Выполните любую инициализацию, которая вам нужна, за пределами вашего кода Pyro. Кэшируйте его где-нибудь. Используйте параметр instance_creator декоратора @behavior для максимального контроля над тем, как и когда создается экземпляр. Вы даже можете подумать о предварительном создании экземпляров сервера самостоятельно и извлечении одного из пула, если хотите? Во всяком случае, один из возможных способов сделать это так:

import Pyro4

def slow_initialization():
    print("initializing stuff...")
    import time
    time.sleep(4)
    print("stuff is initialized!")
    return {"initialized stuff": 42}


cached_initialized_stuff = slow_initialization()


def instance_creator(cls):
    print("(Pyro is asking for a server instance! Creating one!)")
    return cls(cached_initialized_stuff)


@Pyro4.behavior(instance_mode="percall", instance_creator=instance_creator)
class Server:
    def __init__(self, init_stuff):
        self.init_stuff = init_stuff

    @Pyro4.expose
    def work(self):
        print("server: init stuff is:", self.init_stuff)
        return self.init_stuff


Pyro4.Daemon.serveSimple({
    Server: "test.server"
})

Но эта сложность не нужна для вашего сценария, просто инициализируйте вещь (это занимает много времени) и кэшируйте ее где-нибудь. Вместо того, чтобы повторно инициализировать его каждый раз, когда создается новый объект сервера, просто обратитесь к кэшированному предварительно инициализированному результату. Что-то вроде этого;

import Pyro4

def slow_initialization():
    print("initializing stuff...")
    import time
    time.sleep(4)
    print("stuff is initialized!")
    return {"initialized stuff": 42}


cached_initialized_stuff = slow_initialization()


@Pyro4.behavior(instance_mode="percall")
class Server:
    def __init__(self):
        self.init_stuff = cached_initialized_stuff

    @Pyro4.expose
    def work(self):
        print("server: init stuff is:", self.init_stuff)
        return self.init_stuff


Pyro4.Daemon.serveSimple({
    Server: "test.server"
})
person Irmen de Jong    schedule 02.02.2018