Python:线程中的更新参数

Python:线程中的更新参数,python,multithreading,Python,Multithreading,我想知道当这个参数在程序的主线程中得到一个新值时,是否可以启动一个新线程并更新它的参数,所以类似这样: i = 0 def foo(i): print i time.sleep(5) thread.start_new_thread(foo,(i,)) while True: i = i+1 非常感谢你的帮助 参数和其他任何东西一样,只是一个值。传递该值只是对同一个值进行一个新引用,如果对该值进行变异,每个引用都会看到它 全局变量和函数参数都有相同的名称这一事实在这

我想知道当这个参数在程序的主线程中得到一个新值时,是否可以启动一个新线程并更新它的参数,所以类似这样:

i = 0

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

thread.start_new_thread(foo,(i,))

while True:
    i = i+1

非常感谢你的帮助

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

全局变量和函数参数都有相同的名称这一事实在这里并不相关,而且有点令人困惑,因此我将重命名其中一个。另外,您的
foo
函数只执行
打印
一次(可能在您增加值之前),然后睡眠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
进行变异,而是给
i
分配一个新值
0+1
foo
函数仍然引用旧值
0
,该值保持不变

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

例如,您可以使用
set
get
方法编写IntegerHolder类;当您
i.set(i.get()+1)
,而另一个引用执行
i.get()
,它将看到新值

或者您可以使用
列表作为持有者。列表是可变的,包含零个或多个元素。当您执行
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
正在另一个线程中运行这一事实也产生了另一个问题

理论上,线程是同时运行的,它们之间没有任何数据访问顺序。您的主线程可以运行在core 0上,并处理core 0缓存中的
i
副本,而
foo
线程运行在core 1上,并处理core 1缓存中的
i
副本,并且您的代码中没有强制缓存同步的内容

在实践中,你经常会侥幸逃脱,尤其是在CPython。但要想真正知道什么时候可以摆脱它,就必须了解全局解释器锁是如何工作的,解释器是如何处理变量的,甚至(在某些情况下)你的平台的缓存一致性和你的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

最后一件事:如果你创建了一个线程,你需要在以后加入它,否则你不能完全退出。但是你的
foo
线程永远不会退出,所以如果你试图
加入它,你就会永远阻塞它

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

对于更现实的情况,您通常希望在两个线程之间创建某种方式来发送信号。通常,您已经为线程准备好了等待的东西—一个
队列、一个文件对象或它们的集合(通过
选择
),等等。如果没有,只需创建一个受锁保护的标志变量(或条件或任何适当的东西)。

尝试全局变量

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

希望这会有帮助。

你试过这个吗?发生了什么事?建议他使用全局变量来避免处理Python变量的工作方式可能不是一个好主意。@abarnert我也不会在这个例子中使用全局变量。我之所以举全球的例子,是因为我不确定他需要什么。非常感谢你对线程工作原理的清晰解释。现在它更有意义了,而且效果很好!实际上,我指的是foo函数中的while循环。这是。。。真漂亮。。。我认为一个5岁的孩子只有通过阅读你的答案才能学会穿线的基本知识D非常感谢!:)