Add Yield() function to python Threading

I call firebase (query = collection_ref.on_snapshot(on_snapshot)) to setup a callback for receiving changes to a collection. This callback is never called unless you yield.

What is firebase?

Which GUI library do you use?

My own … and not GUI, graphics. It uses GLFW (and OpenGL) under the hood.

1 Like

Thanks!

That looks like a limitation of sched_yield/OpenGL on macOS, then. (Unfortunately, OpenGL is not really native on Mac.)

Do you know of a better OS API than sched_yield? In other words: since you proposed writing a PR, what would that PR call?

Well I don’t know how time.sleep() or os.sched_yield() works in python.

I also don’t know if python firebase uses native threads or threads in python.

I guess my only point is that time.sleep(0) is not guaranteed to yield, but if that is an OS detail that you can’t solve from within python then maybe there is no easy solution.

It’s just not ideal to have to add time.sleep(0.01) to every render loop – but I can live with it.

Technically it yields, but it doesn’t make the OS pick a different thread to schedule next. The OS can choose to give the CPU straight back to you.

I just want to throw in my opinion as someone very familiar with Python and programming in general, but not overly familiar with threading. To me the usage of time.sleep(0) definitely feels like a hack. Having some dedicated method/function for this, even if it was merely a wrapper around time.sleep(0), I would find much better and reassuring that “Yes, this is how this should be done in Python”. There should be an obvious way to do everything, and time.sleep(0) does not feel obvious to me.

Then os.sched_yield is what you want, isn’t it?

But, while time.sleep(0) is as hacky as it sounds to you, IMO sched_yield isn’t much better.
Explicitly yielding execution is a pretty advanced concept, which only makes sense if you know some details about the underlying task scheduler. For general use, the OS and GIL should switch tasks well enough on their own.

If you are waiting for something (to finish or start), the proper way is to use an event or queue, wait for it, and set/send in the thread you’re waiting for.
I don’t know if Firebase can do something like that. If it can’t, an easy imperfect workaround is waiting for a fraction of a second and hoping stuff gets done – but of course, it’s not reliable.
How short can that fraction of a second be? Turns out that 0 tends to work, because time.sleep always releases the GIL and always sleeps for a bit longer than you ask for – both of which are either necessary or useful in the non-zero case too.