Currently, the GIL can be released during object deallocation, either because a C function explicitly does so, or the object has a Python __del__ method. This adds a sharp edge to reasoning about thread-safety with the GIL.
I proposed not allowing context switches during object finalization to simplify the with-GIL concurrency model.
This code is thread-safe with the GIL (g is a global variable)
temp = fancy_object()
g = (1, 2)
g += (3, 4)
# Expect g to be (1,2,3,4) here
but this is not:
temp = fancy_object()
g = (1, 2)
temp = (3, 4)
g += temp
# g might be (3,4) here if another thread sets g to ()
because the assignment temp = (3, 4) code cause fancy_object() to be destroyed and it might have a finalizer.
This is only a problem with CPython; MicroPython and GraalPython have tracing GCs, so only collect objects at safe points.
If we disallow context switching during implicit calls to finalizers, this problem goes away.
The only downside, AFAICT, is that programs that rely on finalizers to clean resources like sockets, and were parallel and relied on running other threads while sockets were being released would see reduced parallelism under the GIL.
Of course, the upside is a reduction in hard to detect race conditions in existing Python programs using the GIL.
Thanks to @pitrou for highlighting this issue: PEP 805: Safe Parallel Python - #79 by pitrou