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

时间:2017-02-01 14:53:33

标签: python multithreading global-variables

我有一个配置文件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是打印)。

如何解决这个问题?

1 个答案:

答案 0 :(得分:3)

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

即使您不这样做,如果在各种模块的导入时间对变量进行更改,则很难跟踪实际的导入顺序。

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

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

threading模块本身提供Event对象,您可以使用该对象让一个线程等待确定,直到另一个线程更改您期望的值:

config.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

注意在上面的代码中,我总是用点分表示法来引用config中的对象。这对"事件"没有任何影响。对象 - 我可以做from config import changed - 因为我正在处理同一个对象的内部状态,所以它会起作用 - 但如果我from config import global_var并将其重新分配给global_var = 7,那只会改变当前模块的上下文点中的local_var名称。 config.local_var仍然引用原始值。

既然你是这样,那么值得一看queue module以及thread-local个对象

当它仍然不起作用时

另一种看不到更改的可能性是,由于并行性不在您的代码中,而是在另一个库中,因此它使用multiprocessing模块而不是线程生成进程。

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

如果是这种情况,则可以在进程间同步(数字,类型化)对象。检查Array and Value类,multiprocessing Queue以便能够发送和接收(主要)任意对象。

(在您的代码中添加import multiprocessing; print(multiprocessing.current_process())行以确定。独立于结果,请建议RandomizedSearchCV文档的维护者明确提及他们为并行操作做了什么)