3

i connect to a client with RPyC and call a Service exposed method with a parameter object. I want to take this object from the exposed method and do somethings with it, but this object is weakly-referenced and at the time i want to access its data: I get a ReferenceError that tells me that the object "weakly-referenced object no longer exists"

How can i safe an object with weak-reference from garbage collection? How can i change it to be strong referenced?

server.py (sending messages)

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 (handling data and put it into a queue)

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

other.py (reading the queue)

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
Paula
  • 95
  • 1
  • 9

2 Answers2

2

I solved the problem of week references (and also the problem of missing attributes) with the following routine:

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    
mib0163
  • 393
  • 3
  • 12
1

This shouldn't happen with primitives (ints, strings, etc.), but can certainly happen with general objects. What you need to do in the server is to obtain the objects, which creates a copy of them in the server process, no longer depending on the reference to be kept in the client process.

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])

This can also be achieved by using deliver in client process.

shx2
  • 61,779
  • 13
  • 130
  • 153
  • 2
    After adding these lines, i got another Error: “ValueError: pickling is disabled”. I found the solution to this problem at [question26899050](http://stackoverflow.com/questions/26899050/multiprocessing-python-with-rpyc-valueerror-pickling-is-disabled) that is to add `conn = rpyc.connect(ip, port, config={"allow_public_attrs": True, "allow_pickle":True})` – Paula Oct 08 '15 at 09:02