【问题标题】:Can python threads access variables in the namespace?python线程可以访问命名空间中的变量吗?
【发布时间】:2012-07-31 23:01:51
【问题描述】:

我有一个创建一堆线程的脚本,运行一个程序来使用线程从队列中运行任务,并从每个线程返回一些东西。我想计算其中有多少成功返回,所以我设置了一个变量“successful=0”,并在队列每次报告任务成功完成时递增它。

但是,我收到“UnboundLocalError: local variable 'successful' referenced before assignment”

发生了什么事?

下面是一些示例代码:

successful = 0

q = Queue(200)
for i in range(100):
    t=Thread(target=foo)
    t.daemon=True
    t.start()
def foo():
    while True:
        task=q.get()
        #do some work
        print task
        successful+=1 # triggers an error
        q.task_done()
for i in range(100):
    q.put("Foo")
q.join()
print successful

【问题讨论】:

    标签: python multithreading scope queue


    【解决方案1】:
    successful+=1
    

    不是线程安全的操作。多个线程尝试递增共享全局变量时,可能会发生冲突,successful 将无法正确递增。

    为避免此错误,请使用锁:

    lock = threading.Lock()
    def foo():
        global successful
        while True:
            ...
            with lock:
                successful+=1 
    

    这里有一些代码来证明 x += 1 不是线程安全的:

    import threading
    lock = threading.Lock()
    x = 0
    def foo():
       global x
       for i in xrange(1000000):
           # with lock:    # Uncomment this to get the right answer
                x += 1
    threads = [threading.Thread(target=foo), threading.Thread(target=foo)]
    for t in threads:
        t.daemon = True    
        t.start()
    for t in threads:
        t.join()
    
    print(x)
    

    产量:

    % test.py 
    1539065
    % test.py 
    1436487
    

    这些结果不一致并且小于预期的 2000000。取消注释锁定会产生正确的结果。

    【讨论】:

      【解决方案2】:

      问题的发生是因为在函数内部分配的变量被认为是该函数的局部变量。如果要修改在foo 之外创建的变量successfull 的值,则需要明确通知解释器您将在函数内使用全局变量。这可以通过以下方式完成:

      def foo():
          global successfull
          while True:
              task=q.get()
              #do some work
              print task
              successful+=1 # triggers an error
              q.task_done()
      

      现在代码应该可以正常工作了。

      【讨论】:

      • 哈哈!我刚刚想通了。无论如何我会给你答案:-)
      【解决方案3】:

      基于Python variable scope error

      我应该把“全局成功”放在“def foo():”下。

      哎呀。

      【讨论】:

        猜你喜欢
        • 2011-07-14
        • 1970-01-01
        • 1970-01-01
        • 2017-01-24
        • 1970-01-01
        • 1970-01-01
        • 2021-04-19
        • 1970-01-01
        • 2020-11-09
        相关资源
        最近更新 更多