python-全局作用域变量:在线程选择它之前,它的值可以更改吗?

在下面的代码中,您看到该线程正在使用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中的值传递给线程,因此,如果i中存储的值发生更改,则不会影响该线程使用的值.

解决方法:

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

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

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

run(arg1, arg2, kwarg1="three times!")

在调用start()时由线程实例创建.如果需要将可变对象(字典,列表,实例)传递给函数,则必须确保重新分配全局变量,而不是就地编辑它.

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

myThread.setMyAttribute('new value')

使用选项2时,您需要警惕比赛条件等,具体取决于方法的作用.每当您正在向线程写入数据或从线程读取数据时使用Locks是一个好主意.

选项3:在首次调用运行时获取全局变量并在本地存储副本

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,不变对象(字符串,数字,元组)通过值传递,可变对象(字典,列表,类实例)通过引用传递.

因此,更改字符串,数字或元组不会影响以前通过该变量传递的任何实例,但是更改dict,列表或实例将起作用.将变量重新分配给其他对象不会影响以前给定旧值的任何内容.

绝对不应该将全局变量用于可能更改的值(如果有的话).基本上,您的示例执行错误的方法.

上一篇:java-在CopyOnWriteArrayList中获取用于添加操作的锁


下一篇:跨线程UI组件调用