【问题标题】:python threading with global variablespython线程与全局变量
【发布时间】:2011-01-20 07:17:10
【问题描述】:

我在编写python线程代码时遇到了一个问题,我写了一些worker线程类,它们都导入了一个像sharevar.py这样的全局文件,我需要一个像regdevid这样的变量来保存 跟踪注册设备ID,当一个线程改变它的值时,其他线程可以 获取新鲜,但结果是:当一个线程更改它的值时,其他线程仍然获得我在 sharevar.py 文件中定义的默认值,为什么? 我有什么问题吗?

# thread a
from UserShare import RegDevID
import threading
class AddPosClass(threading.Thread):
global commands
# We need a pubic sock, list to store the request
def __init__(self, queue):
    threading.Thread.__init__(self)
    self.queue = queue

def run(self):
    while True:
        data = self.queue.get()
        #print data
        RegDevID = data
        #print data
        send_queue.put(data)
        self.queue.task_done()
# thread b
import threading
from ShareVar import send_queue, RegDevID 
"""
AddPos -- add pos info on the tail of the reply
"""
class GetPosClass(threading.Thread):
    global commands
    # We need a pubic sock, list to store the request
    def __init__(self, queue):
        threading.Thread.__init__(self)
        self.queue = queue

    def run(self):
        while True:
            data = self.queue.get()
            #print data
            data = RegDevID
            #print data
            send_queue.put(data)
            self.queue.task_done()
# ShareVar.py
RegDevID = '100'

就是这样,当线程a更改RegDevID时,线程b仍然得到它的默认值。 谢谢高级。

    from ShareVar import RegDevID

class Test():
    def __init__(self):
        pass
    def SetVar(self):
        RegDevID = 999
    def GetVar(self):
        print RegDevID

if __name__ == '__main__':
    test = Test();
    test.SetVar()
    test.GetVar()

ShareVar.py:

RegDevID = 100

结果:

100

为什么?

【问题讨论】:

  • 可能没有什么问题,但也许你应该展示你的代码。
  • 请正确格式化您的代码...

标签: python multithreading variables global


【解决方案1】:

我的猜测是你试图在没有lock 的情况下访问共享变量。如果您没有获取锁并尝试在一个线程中读取共享变量,而另一个线程正在写入它,则该值可能是不确定的。

要补救,请确保在读取或写入线程之前获取线程中的锁。

import threading

# shared lock: define outside threading class
lock = threading.RLock()
# inside threading classes...
# write with lock
with lock: #(python 2.5+)
    shared_var += 1
# or read with lock
with lock:
    print shared_var

了解Python threading

关于范围界定的根本问题的答案:

在您的底部示例中,您遇到了范围界定问题。在SetVar() 中,您将在函数本地创建一个标签RegDevID。在GetVar() 中,您正试图从标签RegDevID 中读取,但它没有被定义。因此,它的范围看起来更高,并找到了在导入中定义的一个。如果您希望它们引用相同的数据,则这些变量需要在相同的范围内。

虽然范围是静态确定的,但它们是动态使用的。 在执行过程中的任何时候,都有 至少是三个嵌套范围 命名空间可直接访问:

最里面的范围,首先搜索,包含本地名称 任何封闭函数的范围,从开始搜索 与最近的封闭范围, 包含非本地的,但也 非全局名称 倒数第二个作用域包含当前模块的全局名称 最外层范围(最后搜索)是包含 内置名称

如果一个名字被声明为全局的,那么所有 参考和作业直接去 到包含 模块的全局名称。否则,所有 在外部发现的变量 最里面的范围是只读的(一个 尝试写入这样的变量 只会创建一个新的本地 最内层范围内的变量, 留下同名的外层 变量不变)。

Read about scoping.

【讨论】:

  • 非常感谢,但是我该如何解决这个问题,我想让我的代码干净,所以每个文件一个线程类,但是它们确实需要共享一些变量,而这些变量应该是可写,有什么办法可以实现吗?
【解决方案2】:

您确定发布了您的实际代码吗?您从两个不同的模块导入 RegDevID:

# thread a
from UserShare import RegDevID

# thread b
from ShareVar import send_queue, RegDevID 

无论哪种方式,您的问题都与线程无关。将“from somemodule import somevar”视为赋值语句。如果模块尚未加载,则大致相当于加载模块的一些魔法:

somevar = sys.modules['somemodule'].somevar

当您从其他模块导入 RegDevID 时,您正在当前模块中创建一个新名称。如果您改变对象,那么该对象的其他用户将看到更改,但如果您在此模块中重新绑定名称,则只会影响本地名称,它不会更改原始模块中的任何内容。

相反,您需要在另一个模块中重新绑定变量:

import ShareVar
...
ShareVar.RegDevID = data

当然,如果你创建一个类来管理你的共享状态,你会发现你会变得更好。

您的第二段代码只是误解了局部变量和全局变量:

def SetVar(self):
    RegDevID = 999

在函数内部,您创建了一个新的局部变量 RegDevID,它与同名的全局变量无关。如果要重新绑定全局变量,请使用 global 语句:

def SetVar(self):
    global RegDevID
    RegDevID = 999

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-13
    • 2015-08-19
    相关资源
    最近更新 更多