为什么当我添加 thread.join() 时,这个多线程代码的行为更安全?

Why this multi-threaded code behaves in a safer way when I add thread.join()?

提问人:Anis Smail 提问时间:11/18/2023 最后编辑:quamranaAnis Smail 更新时间:11/18/2023 访问量:42

问:

import threading

# Shared variable
shared_variable = 0
NUM_THREADS = 999
NUM_INCREMENT = 1_000_000


# Function to increment the shared variable
def increment():
    global shared_variable
    for _ in range(NUM_INCREMENT):
        shared_variable += 1


# Creating multiple threads to increment the shared variable concurrently
threads = []
for _ in range(NUM_THREADS):
    thread = threading.Thread(target=increment)
    threads.append(thread)

for thread in threads:
    thread.start()

for thread in threads:
    thread.join()

# Display the value of the shared variable after concurrent increments
print(
    f"The value of the shared variable is: {shared_variable}, expected : {NUM_THREADS * NUM_INCREMENT}"
)

当我加入线程时,此代码始终打印预期的数字。但是,如果我注释此代码,则某些增量会失败(这是我实际期望的结果!

# for thread in threads:
#    thread.join()

为什么当我添加连接时,此代码以线程安全的方式运行?

Python 线程安全

评论

0赞 quamrana 11/18/2023
当你有 s 时,你正在等待所有线程完成。没有,你冲得太早了。.join()print()
0赞 Anis Smail 11/18/2023
当然,你能把它作为一个答案,让我接受它吗?
0赞 Anis Smail 11/18/2023
也知道为什么这段代码总是计算正确的数字吗?
0赞 Anis Smail 11/18/2023
我试图重现一个并发问题,就像这个用户 stackoverflow.com/a/40072999/6865225
0赞 quamrana 11/18/2023
我能理解这个答案在说什么,但有了你的完整代码,我总是得到正确的答案。

答:

1赞 Solomon Slow 11/18/2023 #1

thread.join()等待完成其工作。如果你要求某人做某事,你会立即抱怨他们没有把工作做好吗?或者你会等到他们完成工作后再做出判断?thread

如果程序在打印值 之前调用每个线程,则线程有时间完成其工作。如果它没有加入线程,并且您在启动线程后立即打印,那么......你得到你得到的任何东西。thread.join()shared_variableshared_variable

1赞 quamrana 11/18/2023 #2

当您注释掉执行所有调用的循环时会发生什么情况,这与您确实有联接时非常相似:thread.join()

您的代码将难以执行在每个线程上调用的循环。这是因为一旦启动了多个线程,它们都倾向于相互阻塞,包括主线程。所有的线程都将缓慢运行,相互竞争,情况越来越糟。thread.start()

我尝试了没有连接的版本,最后一行是这样打印的:

The value of the shared variable is: 997692304, expected : 999000000

这意味着主线程在启动所有线程时非常慢,以至于当主线程退出启动循环并以最终 .print()

如此多的线程完成的原因是它们执行的操作很少(只是增加一个数字),而主线程正在调用,它正在执行更复杂和耗时的事情。thread.start()

相反,在代码完好无损的情况下,调用所有方法意味着主线程将故意等待所有线程完成。这保证了全局变量将具有您期望的所有增量。thread.join()