I was thinking it might be a good idea to have the event loop proactively garbage collect when all coroutines have yielded/are sleeping/waiting for I/O.
The idea being that since garbage collection is stop the world, preemptively garbage collecting so that the gc won’t hit its threshold when the system needs to perform more compute intensive processing.
I think that gc.collect() on every idle iteration could kill performance.
Also, GC is incremental on the main branch IIRC, it stops the world for smaller time period.
I’ve looked into this and a few other options before. I’ve found that disabling the collection entirely (gc.set_threshold(0)) is a pretty reasonable decision in many (but not all) asyncio applications. Those where it isn’t entirely appropriate due to complex reference cycles, but still provides value, you can schedule gc.collect dynamically yourself using any load metrics you have, but you’d be better off changing things to either not have those reference cycles, or to break them yourself in some way when the objects are no longer needed.
If you don’t have complex reference cycles that require the garbage collector to run, and reference counting is enough, the gc probably isn’t running for a noticeable amount of time even without disabling the collection on newer python versions.