From 5dfb9b28f796d03d3ee046eb9fd54566623abcd7 Mon Sep 17 00:00:00 2001 From: Mysteryem Date: Sat, 5 Apr 2025 14:59:39 +0100 Subject: [PATCH] Core: Improve iteration speed of Region.Register objects (#4583) Without implementing __iter__ directly, calling iter() on a Region.Register on Python 3.12 would return a new generator implemented as follows: ```py def __iter__(self) -> int: i = 0 try: while True: v = self[i] yield v i += 1 except IndexError: return None ``` This was determined by disassembling the returned generator with dis.dis() and then constructing a function that disassembles into the same bytecode. The iterator returned by `iter(self._list)` is faster than this generator, so using it slightly improves generation performance on average. Iteration of Region.Register objects is used a lot in `CollectionState.update_reachable_regions` in both of the private _update methods that get called. The performance gain here will vary depending on how many regions a world has and how many exits those regions have on average. For a game like Blasphemous, with a lot of regions and exits, generation of 10 template Blasphemous yamls with `--skip_output --seed 1` and progression balancing disabled went from 19.0s to 16.4s (14.2% reduction in generation duration). --- BaseClasses.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/BaseClasses.py b/BaseClasses.py index 3d000480..84e54d7e 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -1106,6 +1106,9 @@ class Region: def __len__(self) -> int: return self._list.__len__() + def __iter__(self): + return iter(self._list) + # This seems to not be needed, but that's a bit suspicious. # def __del__(self): # self.clear()