python中跨模块和线程的全局变量

2024-05-03

我有一个配置文件 config.py,它包含一个全局变量,即在 config.py 中我有(5 是默认值)

# config.py
globalVar = 5

现在,在模块 run.py 中,我设置全局变量,然后调用打印函数:

# run.py
import config
import test
config.globalVar = 7
test.do_printing()

# test.py
import config
def do_printing():
  print(config.globalVar)

这工作得很好(即打印 7),但如果我使用多个线程进行打印(在 test.py 中),它就不再工作,即线程看不到 run.py 所做的更改(即打印 5)。

如何解决这个问题?


即使在同一线程上运行,您也可能会遇到问题。例如,如果你这样做from config import globalVar相反,如果您在本地模块中重新绑定 globalVar,它只会丢失对配置模块中对象的引用。

即使您不这样做,如果在导入各个模块时发生变量更改,也很难跟踪实际的导入顺序。

当您添加线程时,由于各种竞争条件,这将变得 100% 难以管理。除了竞争条件(即您的一个线程在另一个线程上设置该变量之前读取该变量)或不正确的导入之外,线程不应以您描述的方式影响全局变量更改的可见性。

具有确定性代码的解决方案是使用适合跨线程交换(以及跨线程数据保护)的数据结构。

The threading模块本身提供了Event https://docs.python.org/3/library/threading.html#event-objects可以用于一个线程等待的对象for sure直到其他改变您期望的值:

配置.py:

changed = Event()
changed.clear()

global_var = 5

工作线程中的模块:

import config

def do_things():
    while True:
        config.changed.wait()  # blocks until other thread sets the event
        do_more_things_with(config.global_var)

并在主线程上:

import config

config.global_var = 7
config.changed.set()  # FRees the waiting Thread to run

请注意,在上面的代码中,我总是用点符号引用配置中的对象。这对于“事件”对象没有什么区别 - 我可以做from config import changed- 因为我正在处理同一个对象的内部状态,所以它会起作用 - 但如果我这样做from config import global_var并重新分配它global_var = 7,这只改变了local_var当前模块上下文点中的名称。这config.local_var仍然引用原始值。

既然您已经了解了,那么值得一看队列模块 https://docs.python.org/3/library/queue.html#module-Queue,以及关于线程局部的 https://docs.python.org/3/library/threading.html#thread-local-data objects

当它仍然不起作用时

看不到更改的另一种可能性是,由于并行性不在您的代码中,而是在另一个库中,因此它会使用multiprocessing https://docs.python.org/3/library/multiprocessing.html模块而不是线程。

如果您期望线程并具有多处理生成的进程,那么您遇到的问题将正是您所描述的:全局变量的更改在其他进程中不可见(当然,只是因为每个进程都有自己的变量)。

如果是这种情况,则可以拥有跨进程同步的(数字、类型)对象。检查Array and Value https://docs.python.org/3/library/multiprocessing.html#shared-ctypes-objects课程,以及多重处理Queue https://docs.python.org/3/library/multiprocessing.html#multiprocessing.managers.SyncManager.Queue能够发送和接收(大部分)任意对象。

(Add a import multiprocessing; print(multiprocessing.current_process())行到您的代码以确定。与结果无关,请建议 RandomizedSearchCV 文档的维护者明确提及他们为并行性所做的事情)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

python中跨模块和线程的全局变量 的相关文章

随机推荐