1

I am trying to update a Manager().list() of sets with tuples but having trouble getting anything to add into the set. You can replicate the issue with the below code:

from multiprocessing import Manager

l = Manager().list()
for _ in range(10):
    l.append(set())
l[0].add((10,10)
# returns None
l[0] = {(10,10)}
# sets l[0] to {(10,10}
l[0].add((11,11))
# returns None
l[0].add(10)
# returns None

It seems that for some reason the add method is returning None no matter what. I can't believe this is the expected behavior but perhaps I am just missing something here. In the end all I want to be able to do is:

l[i].add(some_tuple)

And have it properly store the value.

Grr
  • 15,553
  • 7
  • 65
  • 85

2 Answers2

3

The answer is buried in a Note section here (this is the Python 2.7 documentation but the same applies in Python 3.x):

Note Modifications to mutable values or items in dict and list proxies will not be propagated through the manager, because the proxy has no way of knowing when its values or items are modified. To modify such an item, you can re-assign the modified object to the container proxy:

# create a list proxy and append a mutable object (a dictionary)
lproxy = manager.list()
lproxy.append({})
# now mutate the dictionary
d = lproxy[0]
d['a'] = 1
d['b'] = 2
# at this point, the changes to d are not yet synced, but by
# reassigning the dictionary, the proxy is notified of the change
lproxy[0] = d

In your case, once your list-proxy object l has ten sets inside it, you can (in any independent process—note that you cannot do this in two processes simultaneously as these are independent objects too!) do this:

x = l[0]
x.append((10, 10))
l[0] = x

or, if you like:

l[0] = l[0] | set([(10, 10)])

or of course the newfangled Python 3 set syntax:

l[0] = l[0] | {(10, 10)}

Beware: multiprocessing.managers.ListProxy does not (well, cannot, really) implement __ior__ directly on a selected object. Although you can write these using l[0] |= ... if you prefer:

l[0] |= ...

Python actually implements this as:

  1. Fetch the value from l[index] (with locking and/or proxying as needed), then unlock the managed object, returning just the temporary.
  2. Perform the operation on the temporary.
  3. Store the result to l[index] (with locking and/or proxying just like before).

This is why you must be careful not to modify, e.g., l[0] from two different processes at the "same time": one of them will assign first, then the other will assign second, discarding the first-assigned value.

torek
  • 448,244
  • 59
  • 642
  • 775
  • Great answer! I had found the info about re-assigning a modified object, but I was unaware of the consequences for processes. As I am trying to construct a rather large object using processes could you perhaps suggest a better method for sharing an object, or is this a lost cause? – Grr Feb 25 '17 at 07:12
  • There are a bunch of different ways to share things across separate processes, each with different trade-offs. I like to think about the processes as individual people, and any shared resource means "Alice gets up from her desk and goes over to the sharing area and ..." The more "people" who can work independently, the better, and the less often they have to cluster into the sharing-area, the better. The two *styles* of sharing involve either shared *memory* (object stays over in a sharing area, requiring that you carefully arrange to have only one "person" working at a time) and [cont'd] – torek Feb 25 '17 at 17:26
  • ... and sending completed objects through a communications-link, which involves *copying* the object. Large objects obviously have a fair bit of copying overhead, but you can sometimes win more by working "locally at someone's desk" than you pay for the copying. In the end, it usually requires measuring actual performance, to see which works best. – torek Feb 25 '17 at 17:28
0

pardon if i'm not specific with answer, but try this instead

l.insert(index, 'whatever you want to add (tuple maybe)')

index is the place in which you want to add, cheers

P.hunter
  • 1,345
  • 2
  • 21
  • 45
  • Perhaps I wasn't clear in my question. I am trying to add elements to a set inside of a list. Set does not have an insert method. – Grr Feb 24 '17 at 19:43