On 09/12/2018 05:17 AM, Steven D'Aprano wrote:

> Indeed. Each time you call locals(), it returns a new dict with a
snapshot of the current local namespace. Because it all happens inside
the same function call, no external thread can poke inside your current
call to mess with your local variables.

But that's different from setting function.__params__ to passed in
arguments. By definition, each external caller is passing in its own set
of arguments. If you have three calls to the function:

     function(a=1, b=2)  # called by A
     function(a=5, b=8)  # called by B
     function(a=3, b=4)  # called by C

In single-threaded code, there's no problem here:

     A makes the first call;
     the interpreter sets function.__params__ to A's arguments;
     the function runs with A's arguments and returns;

     only then can B make its call;
     the interpreter sets function.__params__ to B's arguments;
     the function runs with B's arguments and returns;

     only then can C make its call;
     the interpreter sets function.__params__ to C's arguments;
     the function runs with C's arguments and returns


but in multi-threaded code, unless there's some form of locking, the
three sets can interleave in any unpredictable order, e.g.:

     A makes its call;
     B makes its call;
     the interpreter sets function.__params__ to B's arguments;
     the interpreter sets function.__params__ to A's arguments;
     the function runs with B's arguments and returns;
     C make its call;
     the interpreter sets function.__params__ to C's arguments;
     the function runs with A's arguments and returns;
     the function runs with C's arguments and returns.


We could solve this race condition with locking, or by making the pair
of steps:

     the interpreter sets function.__params__
     the function runs and returns

a single atomic step. But that introduces a deadlock: once A calls
function(), threads B and C will pause (potentially for a very long
time) waiting for A's call to complete, before they can call the same
function.

I'm not an expert on threaded code, so it is possible I've missed some
non-obvious fix for this, but I expect not. In general, solving race
conditions without deadlocks is a hard problem.

I believe the solution is `threading.local()`, and Python would automatically use it in these situations.

--
~Ethan~
_______________________________________________
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to