【问题标题】:Python 3.5 global variable won't appendPython 3.5 全局变量不会追加
【发布时间】:2016-11-11 16:01:02
【问题描述】:

我正在尝试使用可以在线程/进程完成任务时附加的全局列表。我的主线程可以从中读取,但不能通过函数附加它。基本上我提出请求以获取工作代理,然后尝试将它们保存到列表中,然后在最后打印列表。我已经尽可能地剪掉了。

goodProxyList = ["test"] 


def testProxy(x):
    global goodProxyList
    try:
        test = requests.get('http://someurl.com/', proxies=proxies, timeout=10)
        if test.status_code == 200:
            goodProxyList.append(x)
        else:
            print("Something went wrong! :/" + " From PID: " + str(pid))
    except:
        print("SOMETHING WENT VERY WRONG" + " From PID: " + str(pid))


if __name__ == '__main__':
    ##Setup Stuff happens
    p=Pool(2)
    p.map(testProxy, proxyList)
    for i in goodProxyList:
        print(i)

即使我将 goodProxyList.append(x) 更改为 goodProxyList.append("Anything"),最后两行仍然不会输出“test”。我做错了什么?

编辑:

我通过 brianpck 的帮助找到了答案。正如他所说,似乎进程的工作方式与线程不同。我更改为池线程现在可以完美运行。

#p=Pool(2)
#p.map(testProxy, proxyList)
with concurrent.futures.ThreadPoolExecutor() as executor:
    executor.map(testProxy, proxyList)

【问题讨论】:

  • 你是什么意思,“不能附加到它”?这应该可以正常工作(实际上甚至没有必要明确声明global goodProxyList
  • 对不起,我应该说最后两行的输出仍然只是“测试”,没有别的。
  • @brianpck 要附加到函数范围之外的变量/列表,您必须声明 global goodProxyList
  • @r0xette 不适用于list:尝试x=[]def f(): x.append(1)f()x == [1] 函数范围外
  • Pool() 会发生什么?

标签: python list python-3.x append global


【解决方案1】:

这里的问题是Pool,而不是global

当在函数范围内附加到列表(可变对象)时,列表也会在全局范围内发生变化。 (事实上​​,你甚至不必使用global 关键字:如果函数在它自己的范围内没有找到变量,它会自动在全局范围内查找。)注意一个小“陷阱”在下面的代码,因为map 是一个类似生成器的对象:

x = []

def add_to_x(i):
    x.append(i)

if __name__ == '__main__':
    y = map(add_to_x, [1, 2])
    print(x) # still []
    list(y)
    print(x) # now [1, 2]

以下带有Pool 的简单示例不起作用:

from multiprocessing import Pool

x = []

def add_to_x(i):
    x.append(i)

if __name__ == '__main__':
    p = Pool(2)
    list(p.map(add_to_x, [1, 2]))
    print(x) # prints [] !

为什么? Python multiprocessing global variable updates not returned to parent 的答案很有启发性:这里是相关部分:

当您使用multiprocessing 打开第二个进程时,会创建一个全新的 Python 实例,它具有自己的全局状态。该全局状态不共享,因此子进程对全局变量所做的更改对父进程是不可见的。

您可以通过多种方式潜在地处理这个问题。一种方法是将testProxy 更改为is_good_proxy,这将返回一个布尔值。然后,您可以在主循环中应用附加逻辑。

【讨论】:

  • 啊,很有趣。如果你不能告诉我这是我第一次使用任何类型的多线程/处理。这可以解决(有可能吗?)使用线程池而不是单独的进程?
  • 我不确定:我自己也没有机会使用multiprocessing。但是,如果您的最终目标是附加到您已有的列表中,那么使用 map 肯定是不正确的。
  • 我已经解决了我认为的问题。似乎进程有自己的全局等状态,但线程没有?我通过添加这些行更改为池线程,它现在可以工作:#p=Pool(2) #p.map(testProxy, proxyList) with concurrent.futures.ThreadPoolExecutor() 作为执行器:executor.map(testProxy, proxyList)
  • @user3406647 谢谢。
猜你喜欢
  • 2019-07-24
  • 2021-05-31
  • 2017-03-05
  • 2011-07-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多