奇怪的python线程输出
我得到了一个简单的python程序来分析。它工作正常,随机输出13、14和15(当然)。我明白为什么13和14是印刷出来的,但我不明白15是从哪里来的 请解释一下奇怪的python线程输出,python,multithreading,python-3.x,locking,Python,Multithreading,Python 3.x,Locking,我得到了一个简单的python程序来分析。它工作正常,随机输出13、14和15(当然)。我明白为什么13和14是印刷出来的,但我不明白15是从哪里来的 请解释一下 from threading import Thread import random import time import sys def rwait(): amt = random.uniform(0.01,0.1) time.sleep(amt) x = 0 key = True def lockx():
from threading import Thread
import random
import time
import sys
def rwait():
amt = random.uniform(0.01,0.1)
time.sleep(amt)
x = 0
key = True
def lockx():
global key
while not key:
time.sleep(0)
rwait()
key = False
def unlockx():
global key
key = True
def A():
global x
rwait()
lockx()
reg = x
reg = reg+1
rwait()
x = reg
unlockx()
def B():
global x
rwait()
lockx()
reg = x
reg = reg+2
rwait()
x = reg
unlockx()
def main():
global x
x = 12
p1 = Thread(target=B)
p1.start()
A()
p1.join()
print("x=",x)
for k in range(20):
main()
可能发生三种不同的情况:
- 线程A和B在更改之前读取
,然后x
- 线程A写入其结果(13),然后
- 线程B写入其结果(14)
- 线程A或B首先读取
,然后在另一个线程读取之前写入。结果:15,A读12,加1写13,然后B读13写15,反之亦然x
- 线程A和B在更改之前读取
,然后x
- 线程A写入其结果(13),然后
- 线程B写入其结果(14)
- 线程A或B首先读取
,然后在另一个线程读取之前写入。结果:15,A读12,加1写13,然后B读13写15,反之亦然x
- 可能发生三种不同的情况:
A
在线程B
写入其结果之前读取,而A
在B
写入其结果之后写入
如果收到14,则线程B
在线程A
写入其结果之前读取,而B
在A
写入其结果之后写入
如果收到15,则一个线程在另一个线程写入其结果后读取(以及计算和写入)。此时无法确定两个线程的顺序
然而,更有趣的问题是,为什么锁定机制(
lockx
/unlockx
)显然不起作用。如果它能工作,那么结果总是得到15。您已经在这里演示了一个经典的并发问题。两个写入程序同时工作,因此可能会覆盖另一个写入的数据
如果收到13,则线程A
在线程B
写入其结果之前读取,而A
在B
写入其结果之后写入
如果收到14,则线程B
在线程A
写入其结果之前读取,而B
在A
写入其结果之后写入
如果收到15,则一个线程在另一个线程写入其结果后读取(以及计算和写入)。此时无法确定两个线程的顺序
然而,更有趣的问题是,为什么锁定机制(
lockx
/unlockx
)显然不起作用。如果它能工作的话,你总是会得到15个。你的函数名似乎暗示它们正在执行锁定,而事实并非如此。这有两个原因:
- 对
键的访问不保证原子性
- 即使是,在读取
且其值为键
的时间与使用该键并将其设置为True
的时间之间也存在竞争False
x
仅递增1-B
在A
读取x
后,但在递增的值被存储回之前,已完全执行x
仅增加2-与上面的情况相同,并反转A
和B
x
增加3-A
或B
分别在B
或A
之前执行from threading import Thread, Lock
x = 0
lock = Lock()
def lockx():
global lock
lock.acquire()
def unlockx():
global lock
lock.release()
def A():
global x
lockx()
reg = x
reg = reg+1
x = reg
unlockx()
def B():
global x
lockx()
reg = x
reg = reg+2
x = reg
unlockx()
def main():
global x
x = 12
p1 = Thread(target=B)
p1.start()
A()
p1.join()
print("x=",x)
for k in range(20):
main()
您的函数名似乎暗示它们正在执行锁定,但事实并非如此。这有两个原因:
- 对
键的访问不保证原子性
- 即使是,在读取
且其值为键
的时间与使用该键并将其设置为True
的时间之间也存在竞争False
x
仅递增1-B
在A
读取x
后,但在递增的值被存储回之前,已完全执行x
仅增加2-与上面的情况相同,并反转A
和B
x
增加3-A
或B
分别在B
或A
之前执行from threading import Thread, Lock
x = 0
lock = Lock()
def lockx():
global lock
lock.acquire()
def unlockx():
global lock
lock.release()
def A():
global x
lockx()
reg = x
reg = reg+1
x = reg
unlockx()
def B():
global x
lockx()
reg = x
reg = reg+2
x = reg
unlockx()
def main():
global x
x = 12
p1 = Thread(target=B)
p1.start()
A()
p1.join()
print("x=",x)
for k in range(20):
main()
你认为你的程序到底在做什么?@MichaelFoukarakis同时运行def A()和def B(),并根据定义过程将1或2添加到12。我是python的新手,尤其是多线程。线程通常不能保证并行运行
a()
和B()
——线程本身提供并发性,但不能提供并行性。如果你想以1或2来修改x
,你需要修改你的代码。你认为你的程序到底在做什么?@MichaelFoukarakis同时运行def A()和def B(),并根据定义过程将1或2添加到12。我是python的新手,尤其是multith