0

背景

我正在尝试为Raspberry Pi Stackexchange 上的问题编写解决方案。此人正在创建一个信息亭,并希望 Midori(Raspbian Wheezy 上的浏览​​器)在网络断开然后重新连接时重新加载。为了检查互联网连接,我决定让程序尝试连接到 Google。我使用up根据连接状态分配给 0(向下)或 1(向上)的变量。

我在将新的重新分配up变量发送到线程时遇到问题。我从我的线程中得到一个永久的“Up has not been reassigned”流。

代码

up = -1 #Undefined state

test_net = ("www.google.com", 80)

#Import modules
import subprocess as sub
from time import sleep
import socket
import threading

def reloader(up):
    print "A new thread is born." #Debug
    while True:
        if up == 1:
            print "The system is up."
        elif up == 0:
            print "The system is down."
            #sub.call(["midori", "-e", "Reload"])
        else:
            print "Up has not been reassigned."
        sleep(5)



#Check if internet is up

threading.Thread(target = reloader, args = (up,)).start()

while True:
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    try:
        s.connect(test_net)
        up = 1
        print up
    except socket.error:
        up = 0
        print up
    s.close()
    sleep(10)
4

1 回答 1

0

您的问题是对如何将参数传递给 Python 中的函数的误解。当你这样做时,你期望

up = 1

或者

up = 0

在全局范围内,该reloader函数将在其范围内看到反映在up变量中的更改,因为您将该变量作为参数传递给它。这不是它的工作原理。

您将全局范围内的名称作为参数指向的对象reloader传递给函数,然后在全局范围内为该名称分配了一个新对象。作用域中的名称仍然指向它最初传递的对象,即整数。upupreloader-1

您有两种选择来获得您想要的行为:

1. 通过闭包而不是通过传递参数来共享状态

如果您对代码进行以下两项更改,一切都会按照您的预期进行:

  • 替换def reloader(up):def reloader():
  • 替换threading.Thread(target = reloader, args = (up,)).start()threading.Thread(target = reloader, args = ()).start()

为什么?因为 Python 中的函数可以引用在其父作用域中定义的所有名称。当您需要reloader一个名为 的参数时,您是在up其中定义一个局部变量,从而将同名变量隐藏在父范围中。但是,如果您只是删除参数,那么当您尝试从 inside 读取时,Python 将看到没有这样的局部变量,而是在父范围内查找。因此,外部范围内的分配将在.upreloaderupreloaderupreloader

或者

2. 通过改变作为参数传递的对象来共享状态

不要将整数作为参数传递给,而是传递一个包含 的可变对象, -1然后在您当前将新对象分配给的任何位置修改该对象。您会不时看到建议的一种 hack(通常当人们希望对函数内的变量进行分配时从外部范围可见;您通常会遇到相反的问题,这只能在使用线程时发生)是将变量包装在一个列表中(即初始化为而不是,然后在将其作为参数传递给函数时始终引用而不是除外),这在这种情况下有效。reloader-1upup[-1]-1up[0]up

或者,一个不那么难看的基于可变对象的解决方案可能是使用Valuemultiprocessing 模块中的类,它正是为此目的而存在的。(请注意,通过闭包在进程之间共享状态是不可能的,因为它对于线程来说是不可能的,这使得在使用多处理时使用可变对象来共享状态更加必要。也许这就是为什么多处理模块有Value类但线程模块有没有——据我所知——有类似的东西。)

使用这种方法的工作代码如下所示:

test_net = ("www.google.com", 80)

#Import modules
import subprocess as sub
from time import sleep
import socket
import threading
from multiprocessing import Value

up = Value('i', -1) #Undefined state

def reloader(up):
    print "A new thread is born." #Debug
    while True:
        if up.value == 1:
            print "The system is up."
        elif up.value == 0:
            print "The system is down."
            #sub.call(["midori", "-e", "Reload"])
        else:
            print "Up has not been reassigned."
        sleep(5)



#Check if internet is up

threading.Thread(target = reloader, args = (up,)).start()

while True:
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    try:
        s.connect(test_net)
        up.value = 1
        print up
    except socket.error:
        up.value = 0
        print up
    s.close()
    sleep(10)
于 2013-04-13T22:29:57.660 回答