2013-03-27 117 views
1

我想知道是否有可能开始一个新的线程,并更新其参数时,这种说法得到主的程序的新值更新参数,所以这样的事情:的Python:螺纹

i = 0 

def foo(i): 
    print i 
    time.sleep(5) 

thread.start_new_thread(foo,(i,)) 

while True: 
    i = i+1 

非常感谢您的帮助!

+0

你试过这个吗?发生了什么? – 2013-03-27 20:19:30

回答

1

参数只是一个值,就像其他任何东西一样。传递值只是对同一个值进行新的引用,如果您改变该值,则每个引用都会看到它。

全局变量和函数参数具有相同名称的事实在这里并不相关,并且有点令人困惑,所以我要重命名其中的一个。另外,您的foo函数只能在print一次(甚至可能在您增加值之前),然后休眠5秒钟,然后结束。你可能想要一个循环,否则,你不能确定事情是否正常工作。

所以,这里有一个例子:

i = [] 

def foo(j): 
    while True: 
     print j 
     time.sleep(5) 

thread.start_new_thread(foo,(i,)) 

while True: 
    i.append(1) 

那么,为什么没有你的代码的工作?那么,i = i+1没有突变值0,它将新值值分配给ifoo函数仍旧引用旧值0,该值保持不变。

由于整数是不变的,所以不能直接解决这个问题。但你可以间接地很容易解决:替换整数与某种包装 mutable。

例如,您可以使用setget方法编写IntegerHolder类;当你i.set(i.get() + 1),而另一个参考i.get(),它会看到新的价值。

或者您可以使用list作为持有人。列表是可变的,并保存零个或多个元素。当您执行i[0] = i[0] + 1时,用一个新的整数值替换i[0],但i仍然是相同的列表值,这就是其他参考指向的内容。所以:

i = [0] 

def foo(j): 
    print j[0] 
    time.sleep(5) 

thread.start_new_thread(foo,(i,)) 

while True: 
    i[0] = i[0]+1 

这可能看起来有点乱,但它实际上是一个很常见的Python成语。


同时,foo在另一个线程中运行这一事实会产生另一个问题。

理论上,线程同时运行,并且它们之间没有任何数据访问的排序。您的主线程可以在核心0上运行,并且在核心0的缓存中处理i的副本,而foo线程在核心1上运行,并在核心1的缓存中处理另一个i副本,并且存在你的代码中没有任何东西强制高速缓存同步。

实际上,您经常会忽略这一点,特别是在CPython中。但实际上,当你知道时,你必须学习Global Interpreter Lock是如何工作的,以及解释器如何处理变量以及(在某些情况下)如何处理平台的缓存一致性和C实现的内存模型等工作。所以,你不应该依赖它。正确的做法是使用某种同步机制来防止访问i。作为一个方面说明,你也应该几乎从不使用thread而不是threading,所以我也要切换它。

i = [] 
lock = threading.Lock() 

def foo(j): 
    while True: 
     with lock: 
      print j[0] 
     time.sleep(5) 

t = threading.Thread(target=foo, args=(i,)) 
t.start() 

while True: 
    with lock: 
     i[0] = i[0]+1 

最后一件事:如果你创建一个线程,你需要join它以后,也不能清晰地退出。但是你的foo线程永不退出,所以如果你尝试join它,你将永远阻止。

对于这样的简单情况,有一个简单的解决方案。致电t.start()之前,请拨打t.daemon = True。这意味着当你的主线程退出时,后台线程会在某个任意点自动终止。如果是写入文件或数据库,那显然是一件坏事。但就你而言,它没有做任何持久或危险的事情。

对于更实际的情况,您通常需要创建某种方式来在两个线程之间发送信号。通常你已经得到了线程等待的东西 - Queue,一个文件对象或它们的集合(通过select)等。如果不是,只需创建一个由锁(或条件或其他适当的东西)保护的标志变量)。

+0

非常感谢您对线程工作方式的非常清晰的解释。它现在更有意义,而且效果很棒!实际上,我的意思是在foo函数中使用while循环。 – Tomas 2013-03-29 12:10:44

0

尝试使用全局变量。

i = 0 

def foo(): 
    print i 
    time.sleep(5) 

thread.start_new_thread(foo,()) 

while True: 
    i = i+1 

你也可以传递一个哈希来存放你需要的变量。

args = {'i' : 0} 

def foo(args): 
    print args['i'] 
    time.sleep(5) 

thread.start_new_thread(foo,(args,)) 

while True: 
    args['i'] = arg['i'] + 1 

您可能还想使用线程锁定。

import thread 

lock = thread.allocate_lock() 
args = {'i' : 0} 

def foo(args): 
    with lock: 
     print args['i'] 
    time.sleep(5) 

thread.start_new_thread(foo,(args,)) 

while True: 
    with lock: 
     args['i'] = arg['i'] + 1 

希望这对我有所帮助。

+0

建议他使用全局函数来避免处理Python变量如何工作可能不是一个好主意。 – abarnert 2013-03-27 20:32:47

+0

@abarnert我也不会在这个例子中使用全局。我把这个全球化的例子,因为我不知道他的需求需要什么。 – Drew 2013-03-27 20:53:25