Как заменить слабую ссылку на сильную?

я подключаюсь к клиенту с помощью RPyC и вызываю метод, предоставляемый службой, с объектом параметра. Я хочу взять этот объект из открытого метода и что-то с ним сделать, но этот объект имеет слабую ссылку, и в то время, когда я хочу получить доступ к его данным: я получаю ReferenceError, который говорит мне, что объект «объект со слабой ссылкой не больше не существует"

Как защитить объект со слабой ссылкой от сборки мусора? Как я могу изменить его, чтобы он был строго ссылочным?

server.py (отправка сообщений)

conn = rpyc.connect(ip,port)
bgsrv = rpyc.BgServingThread(conn)
conn.root.my_remote_method(a, b, c)  # a,b,c are integer, strings etc.
time.sleep(0.2)
bgsrv.stop()
conn.close()

client.py (обработка данных и помещение их в очередь)

class MessageService(Service):
    def exposed_my_remote_method(self, a, b, c):
        ThreadedClient.queue.put([a,b,c])

other.py (чтение очереди)

def read_queue(self):
    """ Handle all the messages currently in the queue (if any) """
    while ThreadedClient.queue.qsize():
        try:
            msg = ThreadedClient.queue.get(0)
            self.read_message(msg)
        except Queue.Empty:
            pass

def read_message(self, msg):
    # do something with the data of a, b, c
    res = msg[0] + xy # ReferenceError

person Paula    schedule 07.10.2015    source источник


Ответы (2)


Этого не должно происходить с примитивами (целые числа, строки и т. д.), но, безусловно, может произойти с обычными объектами. Что вам нужно сделать на сервере, так это obtain объекты, которые создают их копии в серверном процессе, больше не завися от ссылки, которая должна храниться в клиентском процессе.

class MessageService(Service):
    def exposed_my_remote_method(self, a, b, c):
        a,b,c = rpyc.classic.obtain([a,b,c])
        ThreadedClient.queue.put([a,b,c])

Этого также можно добиться, используя deliver в клиентском процессе.

person shx2    schedule 08.10.2015
comment
После добавления этих строк я получил еще одну ошибку: «ValueError: травление отключено». Я нашел решение этой проблемы в question26899050, то есть добавить conn = rpyc.connect(ip, port, config={"allow_public_attrs": True, "allow_pickle":True}) - person Paula; 08.10.2015

Я решил проблему недельных ссылок (а также проблему отсутствующих атрибутов) с помощью следующей процедуры:

def rpyc_deep_copy(obj):
    """
    Makes a deep copy of netref objects that come as a result of RPyC remote method calls.
    When RPyC client obtains a result from the remote method call, this result may contain
    non-scalar types (List, Dict, ...) which are given as a wrapper class (a netref object). 
    This class does not have all the standard attributes (e.g. dict.tems() does not work) 
    and in addition the objects only exist while the connection is active. 
    To have a retuned value represented by python's native datatypes and to by able to use it 
    after the connection is terminated, this routine makes a recursive copy of the given object. 
    Currently, only `list` and `dist` types are supported for deep_copy, but other types may be added easily.
    Example:
        s = rpyc.connect(host1, port)
        result = rpyc_deep_copy(s.root.remote_method())
        # if result is a Dict:
        for k,v in result.items(): print(k,v)
    """
    if (isinstance(obj, list)):
        copied_list = []
        for value in obj: copied_list.append(rpyc_deep_copy(value))
        return copied_list
    elif (isinstance(obj, dict)):
        copied_dict = {}
        for key in obj: copied_dict[key] = rpyc_deep_copy(obj[key])
        return copied_dict
    else:
        return obj
    #end if
#end def    
person mib0163    schedule 21.08.2018