-
Notifications
You must be signed in to change notification settings - Fork 190
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RuntimeError when using .remove()
in separate
in very uncommon circumstances
#247
Comments
Thanks for the report, again very comprehensive! I dont have it on top of my head now, but I think there were some reason for set. On the other hand, I do agree that it strange that you can add/remove the same thing twice as long as you do it in a callback during a single timestep, but not otherwise. And its unfortunate that a change would potentially break some code.. I will have to think a bit. (the bug itself should be fixed regardless of course) |
I had time to look some more on this today. There's some tricky cases around this logic...
And the separate is called twice during the same step, then both times the if statement will be true, and floor2 will be added two times to the internal list.. I think this is could be why I had it as set and not list from the beginning. |
I see. There are probably better ways to mitigate that issue, but would require breaking existing code and/or adding new methods. Then, the only possible improvement is to use a Also, checking if something is already added to a space seems to be possibly very expensive since it performs both a copy and a linear time check, when it could possibly be just a constant time hash check. So, a convenient enhancement could perhaps be |
Recently I started to add a benchmark suite to Pymunk, to help me optimize it and Chipmunk. So far its focused on the simulation itself, but as you found now other parts can potentially be optimized. I think the dict/list copy could (should) be removed. I was thinking, maybe it could be enough to have a type hint to show it returns a abc.collections |
As for the bug, I think this would fix it while not breaking any current behavior:
|
A question, does it matter if it removes them in order (dict)? The only visible effect I can think of is the order that separate callbacks invoked by the removals are called. |
It's probably not too important, but it would better match how it would go if the user had used post_step_callbacks instead, as those are ordered (though docs do not say). It is also more intuitive given that users that are calling remove multiple times may not know about the deferring of the remove or that it makes it unordered for the step. |
Also, in my own package I often returned |
Circumstances:
Space.step()
, a shape is removed (such as frompost_solve
callback). The shape removal is automatically delayed until the step finishes.separate
callback.separate
callback, an object is removed.This leads to an error:
What happened was that while the space was iterating over the set of objects to be removed, there was a call to
.remove()
inseparate
. Since the space is locked during this, a new object is put into the set of objects to be removed, but this is illegal as the set is being iterated. This bug is minor, and I can't really think of a practical situation where this might possibly be encountered.In
Space.step()
:pymunk/pymunk/space.py
Lines 588 to 592 in ce59f9a
I'd recommend that any objects removed from these special
separate
calls also be removed immediately after since they can be.Slightly related code improvement
It seems that
_add_later
and_remove_later
areset
s instead oflist
s which doesn't seem like a good choice. Not only does this forget the actual order and is slightly slower, it also allows duplicates (space.remove(body1, body1)
) in a step but not outside a step. So, they should belist
s instead.Recommended fix, assuming above code improvement is applied
With python
>=3.8
, a walrus operator may be used for the loop condition.Minimal reproducible example
The text was updated successfully, but these errors were encountered: