此代码创建一个竞赛条件:
import threading
ITERS = 100000
x = [0]
def worker():
for _ in range(ITERS):
x[0] += 1 # this line creates a race condition
# because it takes a value, increments and then writes
# some inrcements can be done together, and lost
def main():
x[0] = 0 # you may use `global x` instead of this list trick too
t1 = threading.Thread(target=worker)
t2 = threading.Thread(target=worker)
t1.start()
t2.start()
t1.join()
t2.join()
for i in range(5):
main()
print(f'iteration {i}. expected x = {ITERS*2}, got {x[0]}')输出:
$ python3 test.py
iteration 0. expected x = 200000, got 200000
iteration 1. expected x = 200000, got 148115
iteration 2. expected x = 200000, got 155071
iteration 3. expected x = 200000, got 200000
iteration 4. expected x = 200000, got 200000Python3版本:
Python 3.9.7 (default, Sep 10 2021, 14:59:43)
[GCC 11.2.0] on linux我认为吉尔会阻止它,并且不允许两个线程一起运行,直到它们做一些与io相关的事情或者调用C库。至少这是您从医生们中得出的结论。
那么,GIL实际上是做什么的,线程何时并行运行?
发布于 2021-12-27 09:23:52
更好地阅读医生们,我认为答案是:
CPython解释器用于确保一次只执行一个字节码的机制。这通过使对象模型(包括关键的内置类型(如dict) )隐式地避免并发访问,从而简化了CPython实现。锁定整个解释器使解释器更容易被多线程处理,而牺牲了多处理器机器提供的大部分并行性。然而,一些扩展模块,无论是标准的还是第三方的,都是为了在执行压缩或散列等计算密集型任务时释放GIL。同时,在执行I/O时,GIL总是被释放。
我不知道这个字节码的内部结构,但我猜这个字节码的每一行或每一个块都是单独执行的,其他线程也在等待(这使它慢了下来)。但有些行由多个块组成,并不是原子的。
如果运行dis.dis('x[0] += 1'),如下所示
0 LOAD_NAME 0 (x)
2 LOAD_CONST 0 (0)
4 DUP_TOP_TWO
6 BINARY_SUBSCR
8 LOAD_CONST 1 (1)
10 INPLACE_ADD
12 ROT_THREE
14 STORE_SUBSCR
16 LOAD_CONST 2 (None)
18 RETURN_VALUE其中一些是以并发方式执行的,并使竞争条件成为可能。因此,吉尔只保证像list或dict这样的结构的内部不会被破坏。
发布于 2022-09-13 06:44:39
根据我们最后的注释,这似乎已经用python version 3.10和更高的版本修复了(ubuntu,windows)。这个问题已经没有经验了。
然而,在其他情况下,种族条件是可以遵守的。例如:
import threading
import time
x = 10
def increment(by):
global x
local_counter = x
local_counter += by
time.sleep(1)
x = local_counter
print(f'{threading.current_thread().name} inc x {by}, x: {x}')
def main():
# creating threads
t1 = threading.Thread(target=increment, args=(5,))
t2 = threading.Thread(target=increment, args=(10,))
# starting the threads
t1.start()
t2.start()
# waiting for the threads to complete
t1.join()
t2.join()
print(f'The final value of x is {x}')
for i in range(10):
main()它产生了这样的结果:
Thread-56 (increment) inc x 10, x: 20Thread-55 (increment) inc x 5, x: 15
The final value of x is 15
Thread-57 (increment) inc x 5, x: 20Thread-58 (increment) inc x 10, x: 25
The final value of x is 25
Thread-60 (increment) inc x 10, x: 35Thread-59 (increment) inc x 5, x: 30
The final value of x is 30
Thread-61 (increment) inc x 5, x: 35
Thread-62 (increment) inc x 10, x: 40
The final value of x is 40
Thread-64 (increment) inc x 10, x: 50Thread-63 (increment) inc x 5, x: 45
The final value of x is 45但是这里的解决方法是使用asyncio模块来控制代码流。
https://stackoverflow.com/questions/70493438
复制相似问题