On 11 Oct 2021, at 18:58, Thomas Grainger <tagrain@gmail.com> wrote:

Is D1.update(D2) still atomic with this implementation?  https://docs.python.org/3.11/faq/library.html#what-kinds-of-global-value-mutation-are-thread-safe

AFAIK this is already only atomic in specific circumstances, that are more limited than the FAQ appears to claim.

For dict.update to be atomic I’d expect that with two threads performing an update on the same keys you’d end up the update of either thread, but not a mix.

That is:

    Thread 1:  d.update({“a”: 1, “b”: 1})
    Thread 2:  d.update({“a”: 2, “b”: 2})

The result should have d[“a”] == d[“b”].

This can already end up with a mix of the two when “d” has keys that are objects that implement __eq__ in Python, because the interpreter could switch threads while interpreting __eq__. 

A pathological example:

# — start of script —

import threading
import time

stop = False
trigger = False
def runfunc():
    while not stop:
        if trigger:
            d.update({"a": 2, "b": 2 })
            print(d)
            break

t = threading.Thread(target=runfunc)
t.start()


class X(str):
    def __eq__(self, other):
        if threading.current_thread() is t:
            return str.__eq__(self, other)

        global trigger
        trigger = True
        t.join()
        return str.__eq__(self, other)

    def __hash__(self):
        return str.__hash__(self)


d = {X("b"):0}
print("before", d)
d.update({"a":1, "b": 1})
print("after", d)

stop = True
t.join()

# — end of script — 

This prints "after {'b': 1, 'a': 2}” on my machine.

Ronald



On Mon, 11 Oct 2021, 17:54 Sam Gross, <colesbury@gmail.com> wrote:
On Fri, Oct 8, 2021 at 12:04 PM Nathaniel Smith <njs@pobox.com> wrote:
I notice the fb.com address -- is this a personal project or something
facebook is working on? what's the relationship to Cinder, if any?

It is a Facebook project, at least in the important sense that I work on it
as an employee at Facebook. (I'm currently the only person working on it.)
I keep in touch with some of the Cinder devs regularly and they've advised
on the project, but otherwise the two projects are unrelated.
 
Regarding the tricky lock-free dict/list reads: I guess the more
straightforward approach would be to use a plain ol' mutex that's
optimized for this kind of fine-grained per-object lock with short
critical sections and minimal contention, like WTF::Lock. Did you try
alternatives like that? If so, I assume they didn't work well -- can
you give more details?

I'm using WTF::Lock style locks for dict/list mutations. I did an experiment
early on where I included locking around reads as well. I think it slowed down
the pyperformance benchmarks by ~10% on average, but I can't find my notes
so I plan to re-run the experiment.

Additionally, because dicts are used for things like global variables, I'd expect
that locks around reads prevent efficient scaling, but I haven't measured this.

_______________________________________________
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-leave@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at https://mail.python.org/archives/list/python-dev@python.org/message/V76ZRBM6UMGYU7FTNENMOOW7OYEFYQ5Q/
Code of Conduct: http://python.org/psf/codeofconduct/
_______________________________________________
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-leave@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at https://mail.python.org/archives/list/python-dev@python.org/message/5RKLUR2DYJ53OIRX74WVZCVRGW7VUXLF/
Code of Conduct: http://python.org/psf/codeofconduct/


Twitter / micro.blog: @ronaldoussoren
Blog: https://blog.ronaldoussoren.net/