Anton Bryzgalov <tony.bryzgal...@gmail.com> added the comment:

Example code (also is attached to the issue):


import asyncio

async def count_smth(seconds: int) -> int:
    await asyncio.sleep(seconds)
    return seconds * 3

async def small_job(d: dict, key: str, seconds: int) -> None:
    d[key] += await count_smth(seconds)  # <-- strange happens here

async def main() -> None:
     d = dict(key=0)
     await asyncio.gather(
           small_job(d, 'key', 1),
           small_job(d, 'key', 2),
     )
     print(d['key'])  # expected: 0 + 1 * 3 + 2 * 3 = 9, actual: 6

if __name__ == '__main__':
    asyncio.run(main())


Expected output: 0 + 1 * 3 + 2 * 3 = 9. Actual: 6. Seems to be a race condition.

Same happens for other immutable types: str, tuple (when used as values of dict 
instead of int). But works correctly with list and custom class with __iadd__ 
method.

Same effect for treading version (output is the same):


import time
import threading

def count_smth(seconds: int) -> int:
    time.sleep(seconds)
    return seconds * 3

def small_job(d: dict, key: str, seconds: int) -> None:
    d[key] += count_smth(seconds)  # <-- strange happens here

def main() -> None:
    d = dict(key=0)
    t1 = threading.Thread(target=small_job, args=(d, 'key', 1))
    t2 = threading.Thread(target=small_job, args=(d, 'key', 2))
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    print(d['key'])  # expected: 0 + 1 * 3 + 2 * 3 = 9, actual: 6

main()


Inplace operation is expected to occur only at the time when the second operand 
is evaluated.

----------
Added file: https://bugs.python.org/file48718/inplace_bug_threading.py

_______________________________________
Python tracker <rep...@bugs.python.org>
<https://bugs.python.org/issue38817>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to