我try 在多个线程中使用同一个变量,但变量的值在多个线程中没有一致地更新.例如,当线程1将变量更新为1时,线程2无法识别此更改,而是看到旧值.

下面是一个简单的代码示例,说明了这个问题.当用户按下‘a’键时,变量‘Query’应该更新并显示如下:

  1. -oh my 天.
  2. 发文:2011年6月30日星期五

但是,我得到的实际输出只有:

  1. -oh my 天.

你能帮我理解为什么会发生这种情况,以及如何修复吗?

import getch
import threading

QUERY = ""
EXIT_THREAD = False
def input_thread():
    global EXIT_THREAD
    last_query = ""
    while not EXIT_THREAD:
        if last_query != QUERY:
            last_query = QUERY
            print(f"Query: {QUERY}")

thread = threading.Thread(target=input_thread)
thread.start()
while True:
    char = getch.getch()
    if char == "\n":
        break
    elif char == "\x7f":
        QUERY = QUERY[:-1]
    else:
        QUERY += char
    print(f"Query1: {QUERY}")
# kill input thread
EXIT_THREAD = True
thread.join()

推荐答案

问题是getch模块的编码很糟糕.当它阻塞等待输入时,它不会释放the GIL(全局解释器锁),因此您的另一个线程不会运行allowed.与锁同步没有多大帮助;GIL已经在保护对QUERY的访问.

问题是,每次更改为QUERY后,您就会返回到getch,这将锁定GIL.当getch返回时,已经过了足够的时间,GIL被移交immediately,另一个线程判断变化,看到last的变化并报告它,主线程最终获得控制权,但在getch再次锁定它之前,通常不足以导致另一个GIL移交,并且另一个线程永远没有机会运行并看到变化,直到getch下一次返回.这可能会在不同的Python版本中有所不同(何时判断GIL的规则有时会改变),但它总是不稳定的.

正确的解决方案是让getch模块在进行阻塞调用之前在内部释放GIL,但如果做不到这一点,您可以在每个getch调用之前故意以GIL释放的方式阻塞另一个线程来运行一些时间,方法是导入time模块并添加Hibernate ,以便让其他线程有时间看到最新的更改:

while True:
    time.sleep(0.001)  # Explicitly releases GIL for a millisecond
    char = getch.getch()

这会得到您预期的行为,虽然从技术上讲,如果涉及other个线程,则会受到竞争条件的影响,但对于这样的两个线程来说,它是相当可靠的.

Python相关问答推荐

如何随着收件箱的增加动态添加到HTML表的右下角?

将大小为n*512的数组绘制到另一个大小为n*256的数组的PC组件

如何在Power Query中按名称和时间总和进行分组

使用Python和PRNG(不是梅森龙卷风)有效地生成伪随机浮点数在[0,1)中均匀?

收件箱转换错误- polars.exceptions. ComputeHelp- pandera(0.19.0b3)带有polars

如何处理嵌套的SON?

多处理代码在while循环中不工作

如何根据日期和时间将状态更新为已过期或活动?

将DF中的名称与另一DF拆分并匹配并返回匹配的公司

运行回文查找器代码时发生错误:[类型错误:builtin_index_or_system对象不可订阅]

将jit与numpy linSpace函数一起使用时出错

大小为M的第N位_计数(或人口计数)的公式

根据二元组列表在pandas中创建新列

Python—从np.array中 Select 复杂的列子集

Pre—Commit MyPy无法禁用非错误消息

在Python argparse包中添加formatter_class MetavarTypeHelpFormatter时, - help不再工作""""

try 检索blob名称列表时出现错误填充错误""

为什么if2/if3会提供两种不同的输出?

Geopandas未返回正确的缓冲区(单位:米)

在方法中设置属性值时,如何处理语句不可达[Unreacable]";的问题?