程序说明';用户行为(Python)
每次我运行这个程序,它都会输出一个随机数。如果它存款100万次,取款100万次,那么为什么输出不是0? 原因是递增/递减操作实际上分三步执行;首先,解释器获取计数器的当前值,然后计算新值,最后将新值写回变量 如果另一个线程在当前线程获取变量后获得控制权,那么它可能在当前线程执行相同操作之前获取变量、增加变量并将其写回。因为他们都看到了相同的原始值,所以只有一个项目会被考虑。从这里开始 原因是递增/递减操作实际上分三步执行;首先,解释器获取计数器的当前值,然后计算新值,最后将新值写回变量 如果另一个线程在当前线程获取变量后获得控制权,那么它可能在当前线程执行相同操作之前获取变量、增加变量并将其写回。因为他们都看到了相同的原始价值,所以只有一个项目会被考虑。我认为这是一种 你的问题似乎在这里:程序说明';用户行为(Python),python,multithreading,python-2.7,Python,Multithreading,Python 2.7,每次我运行这个程序,它都会输出一个随机数。如果它存款100万次,取款100万次,那么为什么输出不是0? 原因是递增/递减操作实际上分三步执行;首先,解释器获取计数器的当前值,然后计算新值,最后将新值写回变量 如果另一个线程在当前线程获取变量后获得控制权,那么它可能在当前线程执行相同操作之前获取变量、增加变量并将其写回。因为他们都看到了相同的原始值,所以只有一个项目会被考虑。从这里开始 原因是递增/递减操作实际上分三步执行;首先,解释器获取计数器的当前值,然后计算新值,最后将新值写回变量 如果另一
import threading
shared_balance = 0
class Deposit(threading.Thread):
def run(self):
for i in xrange(1000000):
global shared_balance
balance = shared_balance
balance += 100
shared_balance = balance
class Withdraw(threading.Thread):
def run(self):
for i in xrange(1000000):
global shared_balance
balance = shared_balance
balance -= 100
shared_balance = balance
thread1 = Deposit()
thread2 = Withdraw()
thread1.start()
thread2.start()
thread1.join()
thread2.join()
print shared_balance
考虑一下,当执行顺序如下时会发生什么:
balance = shared_balance
balance += 100
共享余额的更新丢失了我认为这有点像
你的问题似乎在这里:
import threading
shared_balance = 0
class Deposit(threading.Thread):
def run(self):
for i in xrange(1000000):
global shared_balance
balance = shared_balance
balance += 100
shared_balance = balance
class Withdraw(threading.Thread):
def run(self):
for i in xrange(1000000):
global shared_balance
balance = shared_balance
balance -= 100
shared_balance = balance
thread1 = Deposit()
thread2 = Withdraw()
thread1.start()
thread2.start()
thread1.join()
thread2.join()
print shared_balance
考虑一下,当执行顺序如下时会发生什么:
balance = shared_balance
balance += 100
共享余额的更新丢失请尝试lock.acquire()
和lock.release()
解决您的问题:
抱歉复制了一些代码。我已标记这些更改:
[...]
deposit thread: balance = shared_balance
withdraw thread: balance -= 100
deposit thread: balance += 100
deposit thread: shared_balance = balance
withdraw thread: shared_balance = balance
lock=threading.lock()
类别存款(线程。线程):
def运行(自):
对于X范围内的i(1000000):
lock.acquire()尝试lock.acquire()
和lock.release()
来解决您的问题:
抱歉复制了一些代码。我已标记这些更改:
[...]
deposit thread: balance = shared_balance
withdraw thread: balance -= 100
deposit thread: balance += 100
deposit thread: shared_balance = balance
withdraw thread: shared_balance = balance
lock=threading.lock()
类别存款(线程。线程):
def运行(自):
对于X范围内的i(1000000):
lock.acquire()您需要使用以安全访问变量:
lock = threading.Lock()
class Deposit(threading.Thread):
def run(self):
for i in xrange(1000000):
lock.acquire() <==============================
global shared_balance
balance = shared_balance
#print "[thread1] old: " + str(balance)
balance += 100
#print "[thread1] new: " + str(balance)
shared_balance = balance
#print "[thread1] shared: " + str(shared_balance)
lock.release() <==============================
class Withdraw(threading.Thread):
def run(self):
for i in xrange(1000000):
lock.acquire() <==============================
global shared_balance
balance = shared_balance
#print "[thread2] old: " + str(balance)
balance -= 100
#print "[thread2] new: " + str(balance)
shared_balance = balance
#print "[thread2] shared: " + str(shared_balance)
lock.release() <==============================**
输出:
from threading import Thread, Lock
shared_balance = 0
class Deposit(Thread):
def __init__(self, lock):
super(Deposit, self).__init__()
self.lock = lock
def run(self):
global shared_balance
for i in xrange(1000000):
with self.lock:
shared_balance += 100
class Withdraw(Thread):
def __init__(self, lock):
super(Withdraw, self).__init__()
self.lock = lock
def run(self):
global shared_balance
for i in xrange(1000000):
with self.lock:
shared_balance -= 100
shared_lock = Lock()
thread1 = Deposit(shared_lock)
thread2 = Withdraw(shared_lock)
thread1.start()
thread2.start()
thread1.join()
thread2.join()
print shared_balance
另外,请查看为以下内容生成的字节码:
>>> 0
“a+=10”的字节码:
在Python中,字节码执行不能被抢占。它使线程的使用变得非常方便。但在这种情况下,需要执行4个字节码才能执行“+=”操作。这意味着任何其他线程的任何其他字节码都不能在这些字节码之间执行。这就是它不安全的原因,也是您应该使用锁的原因 您需要使用以安全访问变量:
lock = threading.Lock()
class Deposit(threading.Thread):
def run(self):
for i in xrange(1000000):
lock.acquire() <==============================
global shared_balance
balance = shared_balance
#print "[thread1] old: " + str(balance)
balance += 100
#print "[thread1] new: " + str(balance)
shared_balance = balance
#print "[thread1] shared: " + str(shared_balance)
lock.release() <==============================
class Withdraw(threading.Thread):
def run(self):
for i in xrange(1000000):
lock.acquire() <==============================
global shared_balance
balance = shared_balance
#print "[thread2] old: " + str(balance)
balance -= 100
#print "[thread2] new: " + str(balance)
shared_balance = balance
#print "[thread2] shared: " + str(shared_balance)
lock.release() <==============================**
输出:
from threading import Thread, Lock
shared_balance = 0
class Deposit(Thread):
def __init__(self, lock):
super(Deposit, self).__init__()
self.lock = lock
def run(self):
global shared_balance
for i in xrange(1000000):
with self.lock:
shared_balance += 100
class Withdraw(Thread):
def __init__(self, lock):
super(Withdraw, self).__init__()
self.lock = lock
def run(self):
global shared_balance
for i in xrange(1000000):
with self.lock:
shared_balance -= 100
shared_lock = Lock()
thread1 = Deposit(shared_lock)
thread2 = Withdraw(shared_lock)
thread1.start()
thread2.start()
thread1.join()
thread2.join()
print shared_balance
另外,请查看为以下内容生成的字节码:
>>> 0
“a+=10”的字节码:
在Python中,字节码执行不能被抢占。它使线程的使用变得非常方便。但在这种情况下,需要执行4个字节码才能执行“+=”操作。这意味着任何其他线程的任何其他字节码都不能在这些字节码之间执行。这就是它不安全的原因,也是您应该使用锁的原因 如果使用两个线程来操作一个共享_平衡,结果是无法预料的
比如说,,
现在共享的\u余额=0
如果线程1执行以下操作:
6 LOAD_GLOBAL 0 (a) # Load global "a" UNSAFE ZONE
9 LOAD_CONST 2 (10) # Load value "10" UNSAFE ZONE
12 INPLACE_ADD # Perform "+=" UNSAFE ZONE
13 STORE_GLOBAL 0 (a) # Store global "a"
16 LOAD_CONST 0 (None) # Load "None"
19 RETURN_VALUE # Return "None"
现在线程1平衡=100共享\u平衡=0
然后转到thread2:
balance = shared_balance
balance += 100
shared_balance = balance
现在thread2 balance=-100 shared_balance=0
然后转到thread1:
balance = shared_balance
balance -= 100
现在共享的_余额=100
最后它变成了thread2:
balance = shared_balance
balance += 100
shared_balance = balance
现在共享的_余额=-100
因此,当循环结束时,结果不是0
如果希望得到结果0,则应为每个循环添加一个锁。如果使用两个线程到运算符一个共享\u平衡,则结果是无法预料的
比如说,,
现在共享的\u余额=0
如果线程1执行以下操作:
6 LOAD_GLOBAL 0 (a) # Load global "a" UNSAFE ZONE
9 LOAD_CONST 2 (10) # Load value "10" UNSAFE ZONE
12 INPLACE_ADD # Perform "+=" UNSAFE ZONE
13 STORE_GLOBAL 0 (a) # Store global "a"
16 LOAD_CONST 0 (None) # Load "None"
19 RETURN_VALUE # Return "None"
现在线程1平衡=100共享\u平衡=0
然后转到thread2:
balance = shared_balance
balance += 100
shared_balance = balance
现在thread2 balance=-100 shared_balance=0
然后转到thread1:
balance = shared_balance
balance -= 100
现在共享的_余额=100
最后它变成了thread2:
balance = shared_balance
balance += 100
shared_balance = balance
现在共享的_余额=-100
因此,当循环结束时,结果不是0
如果希望得到结果0,则应为每个循环添加一个锁。密切相关的可能重复:假设两个线程交替;相反,它们几乎可以同时读写。两个线程都读取一个数字,然后都更改数字并写入。两次写入中的一次写入将丢失,因为另一次写入将覆盖平衡。密切相关的,可能的重复:假设两个线程交替;相反,它们几乎可以同时读写。两个线程都读取一个数字,然后都更改数字并写入。两次写入中的一次写入将丢失,因为另一次写入将覆盖余额。