如果你依赖一个拥有全局解释器锁(即CPython)的Python实现并编写多线程代码,那么你真的需要锁吗?
如果GIL不允许并行执行多条指令,那么共享数据难道不需要保护吗?
如果这是一个愚蠢的问题,很抱歉,但这是我一直想知道的关于多处理器/核心计算机上的Python的事情。
同样的事情也适用于任何其他具有GIL的语言实现。
发布于 2008-09-19 20:34:41
如果你在线程之间共享状态,你仍然需要锁。GIL只在内部保护解释器。你仍然可以在你自己的代码中有不一致的更新。
例如:
#!/usr/bin/env python
import threading
shared_balance = 0
class Deposit(threading.Thread):
def run(self):
for _ in xrange(1000000):
global shared_balance
balance = shared_balance
balance += 100
shared_balance = balance
class Withdraw(threading.Thread):
def run(self):
for _ in xrange(1000000):
global shared_balance
balance = shared_balance
balance -= 100
shared_balance = balance
threads = [Deposit(), Withdraw()]
for thread in threads:
thread.start()
for thread in threads:
thread.join()
print shared_balance
在这里,您的代码可能会在读取共享状态(balance = shared_balance
)和写回更改后的结果(shared_balance = balance
)之间中断,从而导致更新丢失。结果是共享状态的随机值。
为了使更新保持一致,run方法需要锁定读取-修改-写入部分周围的共享状态(在循环内),或者使用some way to detect when the shared state had changed since it was read。
发布于 2008-12-22 09:49:36
这样想吧:
在单处理器计算机上,多线程发生的方式是挂起一个线程,然后以足够快的速度启动另一个线程,使其看起来像是同时运行。这就像使用GIL的Python :只有一个线程在实际运行。
问题是线程可以在任何地方挂起,例如,如果我想计算b= (a + b) * 3,这可能会产生类似如下的指令:
1 a += b
2 a *= 3
3 b = a
现在,假设它在一个线程中运行,该线程在第1行或第2行之后挂起,然后另一个线程开始运行:
b = 5
然后,当另一个线程恢复时,b将被旧的计算值覆盖,这可能不是预期的。
因此,您可以看到,即使它们实际上没有同时运行,您仍然需要锁定。
发布于 2008-09-19 20:11:19
您仍然需要使用锁(您的代码可能在任何时候被中断以执行另一个线程,这可能会导致数据不一致)。GIL的问题是它阻止Python代码同时使用更多的内核(或多个处理器,如果它们可用的话)。
https://stackoverflow.com/questions/105095
复制相似问题