在下面的代码中,您看到该线程正在使用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,列表或实例将起作用.将变量重新分配给其他对象不会影响以前给定旧值的任何内容.
绝对不应该将全局变量用于可能更改的值(如果有的话).基本上,您的示例执行错误的方法.