python线程与全局变量
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4744426/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
python threading with global variables
提问by liunx
i encountered a problem when write python threading code, that i wrote some workers threading classes, they all import a global file like sharevar.py, i need a variable like regdevid to keep tracking the register device id, then when one thread change it's value, then other threads can get it fresh, but the result is that: when one thread change it's value, the others still get the default value i defined in sharevar.py file, why? anything wrong with me?
我在写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'
That's it, when thread a changed the RegDevID, thread b still get it's default value. Thanks advanced.
就是这样,当线程 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()
The ShareVar.py:
ShareVar.py:
RegDevID = 100
The result:
结果:
100
why?
为什么?
采纳答案by Duncan
Are you sure you posted your actual code? You imported RegDevID from two different modules:
你确定你发布了你的实际代码?您从两个不同的模块导入 RegDevID:
# thread a
from UserShare import RegDevID
vs
对比
# thread b
from ShareVar import send_queue, RegDevID
Either way, your problam has nothing to do with threading. Think of 'from somemodule import somevar' as an assignment statement. Roughly equivalent to some magic to load the module if it isn't already loaded followed by:
无论哪种方式,您的问题都与线程无关。将“from somemodule import somevar”视为赋值语句。如果模块尚未加载,则大致相当于加载模块的一些魔法,然后是:
somevar = sys.modules['somemodule'].somevar
When you import RegDevID from the other module you are creating a fresh name in the current module. If you mutate the object then other users of the object will see the changes, but if you rebind the name in this module then that only affects the local name it doesn't change anything in the original module.
当您从其他模块导入 RegDevID 时,您正在当前模块中创建一个新名称。如果您改变对象,则该对象的其他用户将看到更改,但如果您重新绑定此模块中的名称,则只会影响本地名称,它不会更改原始模块中的任何内容。
Instead you need to rebind the variable in another module:
相反,您需要在另一个模块中重新绑定变量:
import ShareVar
...
ShareVar.RegDevID = data
Except of course you'll find you get on much better if you create a class to manage your shared state.
当然,如果你创建一个类来管理你的共享状态,你会发现你会变得更好。
Your second bit of code is ejust misunderstanding local and global variables:
你的第二段代码只是误解了局部和全局变量:
def SetVar(self):
RegDevID = 999
inside the function you created a new local variable RegDevID which is nothing to do with the global variable of the same name. Use the globalstatement if you want to rebind a global variable:
在函数内部,您创建了一个新的局部变量 RegDevID,它与同名的全局变量无关。global如果要重新绑定全局变量,请使用以下语句:
def SetVar(self):
global RegDevID
RegDevID = 999
回答by atp
My guess is you are trying to access the shared variable without a lock. If you do not acquire a lock and attempt to read a shared variable in one thread, while another thread is writing to it, the value could be indeterminate.
我的猜测是您正在尝试访问没有lock. 如果您没有获取锁并尝试在一个线程中读取共享变量,而另一个线程正在向它写入,则该值可能是不确定的。
To remedy, make sure you acquire a lock in the thread before reading or writing to it.
要补救,请确保在读取或写入线程之前获取线程中的锁。
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
Read about Python threading.
阅读Python 线程。
Answer to your bottom problem with scoping:
回答您的范围界定问题:
In your bottom sample, you are experiencing a problem with scoping. In SetVar(), you are create a label RegDevIDlocal to the function. In GetVar(), you are attempting to read from a label RegDevIDbut it is not defined. So, it looks higher in scope and finds one defined in the import. The variables need to be in the same scope if you hope to have them reference the same data.
在您的底部示例中,您遇到了范围界定问题。在 中SetVar(),您将创建RegDevID函数的局部标签。在 中GetVar(),您试图从标签中读取RegDevID但未定义。因此,它在范围上看起来更高,并找到了在导入中定义的一个。如果您希望变量引用相同的数据,则变量需要在相同的范围内。
Although scopes are determined statically, they are used dynamically. At any time during execution, there are at least three nested scopes whose namespaces are directly accessible:
the innermost scope, which is searched first, contains the local names the scopes of any enclosing functions, which are searched starting with the nearest enclosing scope, contains non-local, but also non-global names the next-to-last scope contains the current module's global names the outermost scope (searched last) is the namespace containing built-in names
If a name is declared global, then all references and assignments go directly to the middle scope containing the module's global names. Otherwise, all variables found outside of the innermost scope are read-only (an attempt to write to such a variable will simply create a new local variable in the innermost scope, leaving the identically named outer variable unchanged).
尽管范围是静态确定的,但它们是动态使用的。在执行过程中的任何时候,至少有三个嵌套的作用域可以直接访问其命名空间:
首先搜索的最里面的范围包含本地名称 任何封闭函数的范围,从最近的封闭范围开始搜索,包含非本地,但也包含非全局名称 倒数第二个范围包含当前模块的全局名称最外层范围(最后搜索)是包含内置名称的命名空间
如果一个名称被声明为全局的,那么所有的引用和赋值都会直接进入包含模块全局名称的中间作用域。否则,在最内层范围之外找到的所有变量都是只读的(尝试写入这样的变量只会在最内层范围内创建一个新的局部变量,而使同名的外层变量保持不变)。

