在下面的代码中,您会看到线程正在使用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
中存储的值发生更改,则线程的值为与之合作不受影响。
答案 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当然不应该用于可能发生变化的值(如果有的话)。基本上你的例子是错误的做法。