[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

Re: [pygame] Subtle Memory Bug



It's probably not the uniqueness of ID numbers that's breaking his code, it's the fact that he has two different generations in the same data structure. That's simply not how you should do what he's trying to do.

-bob

On Jul 10, 2006, at 4:51 PM, andrew baker wrote:

If you're using ID numbers, they really should be unique.

On 7/10/06, Bob Ippolito <bob@xxxxxxxxxx> wrote:

On Jul 10, 2006, at 2:27 PM, Kris Schnee wrote:

> I've just solved a tricky bug (I think) whose solution might help
> others
> who encounter a similar problem.
>
> I was playing with cellular automata, a bunch of "tribes" that move
> and
> grow as squares on a grid. Each tribe was stored in a game object,
> in a
> dictionary, by an ID number. I had a loop that made each tribe take an
> action, like so:
>
> for tribe in self.alltribes.values(): ## Line 1
>     ## Make sure tribe is still in play before activating.
>     if tribe.ID in self.alltribes.keys(): ## Line 2
>         tribe.Go()
> self.age += 1
>
> Some events would cause a tribe to merge with another, deleting
> both and
> creating a new tribe with a new ID value. Other events would create a
> new tribe. I was getting a strange error in which a tribe would try to
> move from coordinates that it wasn't actually at, crashing the
> program.
> I narrowed down that this only happened when a tribe was deleted, and
> then another tribe was randomly created with the same ID in the
> same turn.
>
> The reason seems to be this. Line 1 creates a list of tribes when the
> loop begins, _containing the tribe objects themselves_. When a game
> event deletes a tribe, it's still present in memory until the end
> of the
> loop... so the loop checks the deleted tribe's ID, sees that there's
> still a tribe with that ID (the newly created one), and runs _the
> deleted tribe_, which shouldn't happen. So I changed line 2 to:
>
> if tribe in self.alltribes.values(): ## Line 2b
>
> This way, the tribe is checked not as an ID#, but as a Python object,
> against the list of objects in self.alltribes.values. If the tribe is
> deleted, it won't show up in the list when it's checked, so the test
> will fail as it should.

Well, I'm not sure I'd say that's a good solution either way. You
should think *really* carefully about iterating over a dictionary
you're also mutating. It also seems like a really strange way to do
cellular automata, since you're letting the hash order of the
dictionary influence the algorithm. The way you're using the dict is
really strange too, "foo in dict.keys()" is an order of magnitude
slower than "foo in dict".. and checking existence in values() is a
pretty good sign you're doing something wrong or using the wrong kind
of data structure.

I'd create a new alltribes dict on every generation. It'd be faster
than what you're doing now, be more deterministic, and a lot easier
to get right.

I wouldn't classify this as a memory bug either. It doesn't really
have anything to do with memory.

-bob




--
Andrew Ulysses Baker
"failrate"