全局范围的变量:它的值是否可以在被线程拾取之前发生变化?

时间:2009-08-04 16:49:40

标签: python multithreading scope

在下面的代码中,您会看到线程正在使用pickledList并在全局范围内设置。

如果线程正在使用的变量是在最终while循环中的某个位置动态设置的,那么它的值是否可能在线程使用之前发生变化?如何在循环中动态设置值,将其发送到线程并确保在线程使用它之前它的值不会改变?

import pickle
import Queue
import socket
import threading

someList = [ 1, 2, 7, 9, 0 ]
pickledList = pickle.dumps ( someList )

class ClientThread ( threading.Thread ):
   def run ( self ):
      while True:
         client = clientPool.get()
         if client != None:
            print 'Received connection:', client [ 1 ] [ 0 ]
            client [ 0 ].send ( pickledList )
            for x in xrange ( 10 ):
               print client [ 0 ].recv ( 1024 )
            client [ 0 ].close()
            print 'Closed connection:', client [ 1 ] [ 0 ]


clientPool = Queue.Queue ( 0 )

for x in xrange ( 2 ):
   ClientThread().start()

server = socket.socket ( socket.AF_INET, socket.SOCK_STREAM )
server.bind ( ( '', 2727 ) )
server.listen ( 5 )

while True:
   clientPool.put ( server.accept() )

编辑:

这是我问题的一个更好的例子。如果你运行它,有时值会在线程输出之前发生变化,导致一些值被跳过:

from threading import Thread
class t ( Thread ):
    def run(self):
        print "(from thread) ",
        print i

for i in range(1, 50):    
    print i
    t().start()

如何将i中的值传递给线程,使其不再绑定到变量,这样如果i中存储的值发生更改,则线程的值为与之合作不受影响。

1 个答案:

答案 0 :(得分:3)

选项1:您可以在实例化时将参数传递给每个线程:

ClientThread(arg1, arg2, kwarg1="three times!").start()

在这种情况下,您的run方法将被调用:

run(arg1, arg2, kwarg1="three times!")
调用start()时由Thread实例

。如果需要将可变对象(dicts,lists,instances)传递给函数,则必须确保重新分配全局变量,将其编辑到位。

选项2:您可以在ClientThread个对象上设置实例变量:

myThread.setMyAttribute('new value')

使用选项2,您需要警惕竞争条件等,具体取决于方法的作用。 Lock。

选项3:首次调用run时抓取全局并在本地存储副本

run(self):
    localVar = globalVar # only for immutable types
    localList = globalList[:] # copy of a list
    localDict = globalDict.copy() # Warning! Shallow copy only!

如果给定线程的值在其生命周期内永远不需要更改,则选项1是正确的方法,如果值确实需要更改,则选项2。选项3是一个黑客。

关于通常传递变量/值,你必须记住Python,不可变对象(字符串,数字,元组)通过值传递和可变对象(dicts,lists,class instances)通过引用传递。

因此,更改字符串,数字或元组不会影响先前传递该变量的任何实例,但是更改字典,列表或实例会这样做。将变量重新分配给不同的对象不会影响先前给定旧值的任何内容。

Globals当然不应该用于可能发生变化的值(如果有的话)。基本上你的例子是错误的做法。