CPython 2.7: Weakset data changing size during internal iteration

Terry Reedy tjreedy at udel.edu
Fri Jun 1 18:42:22 EDT 2012


On 6/1/2012 11:23 AM, Temia Eszteri wrote:
> I've got a bit of a problem - my project uses weak sets in multiple
> areas, the problem case in particular being to indicate what objects
> are using a particular texture, if any, so that its priority in OpenGL
> can be adjusted to match at the same time as it being (de)referenced
> by any explicit calls.
>
> Problem is that for certain high-frequency operations, it seems
> there's too much data going in and out for it to handle - the
> following traceback is given to me (project path changed to protect
> the innocent):
>
> Traceback (most recent call last):
>    File "C:\foo\bar\game.py", line 279, in update
>      self.player.update()
>    File "C:\foo\bar\player.py", line 87, in update
>      PlayerBullet((self.x + 8, self.y + 9), 0, self.parent)
>    File "C:\foo\bar\player.py", line 96, in __init__
>      self.sprite = video.Sprite("testbullet", 0)
>    File "C:\foo\bar\video.py", line 95, in __init__
>      self.opengl_id = reference_texture(self, target)
>    File "C:\foo\bar\video.py", line 310, in reference_texture
>      if not video_handler.textures[target].references:

I gather that the .references attribute is sometimes/always a weakset. 
To determine its boolean value, it computes its length. For regular 
sets, this is sensible as .__len__() returns a pre-computed value.

>    File "C:\Python27\lib\_weakrefset.py", line 66, in __len__
>      return sum(x() is not None for x in self.data)

Given that len(weakset) is defined (sensibly) as the number of currently 
active members, it must count. weakset should really have .__bool__ 
method that uses any() instead of sum(). That might reduce, but not 
necessarily eliminate your problem.

>    File "C:\Python27\lib\_weakrefset.py", line 66, in<genexpr>
>      return sum(x() is not None for x in self.data)
> RuntimeError: Set changed size during iteration

I can think of two reasons:

1. You are using multiple threads and another thread does something to 
change the size of the set during the iteration. Solution? put a lock 
around the if-statement so no other thread can change self.data during 
the iteration.

2. Weakset members remove themselves from the set before returning None. 
(Just a thought, in case you are not using threads).

-- 
Terry Jan Reedy




More information about the Python-list mailing list