如何在不使用队列的情况下将字典传递给可以在外部更改的Python线程

0 投票
3 回答
1998 浏览
提问于 2025-04-18 01:33

我想在我的多个线程之间共享一个字典,但不想使用队列。我之前是通过创建一个包含对象的线程来实现的,但现在我想只用对象中的一个函数来创建线程,而不是使用整个对象。我的简化代码如下:

 #!/usr/bin/python
 import threading
 import time


 class WebSocket(threading.Thread):
     def __init__(self, server=1, sock=1, address=1):
         self.s1=server
         self.s2=sock
         self.s3=address
         print "salam"


     def CheckThread(self):
         self.a={'1':1, '2':2}
         s=threading.Thread(target=self.SockFun, kwargs=self.a)
         s.deamon=True
         s.start()

         while(1):
             self.a['1']=self.a['1']+1
             time.sleep(1)

     def SockFun(self,**kwargs):
         pass

 class SimpleEcho(WebSocket):
     def SockFun(self,**kwargs):
         while(1):
             print kwargs
             time.sleep(1)

     def handleMessage(self):
         self.CheckThread()

 s=SimpleEcho()
 s.handleMessage()

我在线程中打印的字典元素 '1' 的值并没有像我预期的那样增加:

3 个回答

1

使用 kwargs 这个机制会把字典里的元素复制到 SimpleEcho 里面。一旦复制过去了,原来的内容再怎么改也不会影响到打印出来的结果。想要快速验证这一点,可以把 print kwargs 改成 print self.a 来看看。

另外,你可以把 kwargs=self.a 改成 kwargs={"argh":self.a}。这样做的话,kwargs 还是会被复制,但这个复制的内容会包含对原始 self.a 的引用。

还有,你是不是应该使用某种锁定机制呢?

1

当你使用 ** 这种写法时,字典会被复制,这就是为什么你不能那样做的原因。

>>> foo = {'bar': 'baz'}
>>> def spam(**kwargs):
...     print(kwargs is foo)
... 
>>> spam(**foo)
False

你需要使用一个可变类型,比如列表,作为字典中的一个项(你可以这样做,因为复制的是浅拷贝:它只复制字典本身,而不复制里面的内容)。

>>> import time
>>> import threading
>>> def spam(**kwargs):
...     while True:
...         time.sleep(10)
...         print(kwargs['bar'][0])
... 
>>> foo = {'bar': ['baz']}
>>> threading.Thread(target=spam, kwargs=foo).start()
>>> baz

>>> foo['bar'][0] = 'qux'
>>> qux
qux
qux
1

这不是线程问题。当你通过关键字参数(kwargs)传递self.a这个字典时,它并不是通过引用传递的,而是被复制了一份。

>>> mydict = {'foo': 'bar'}
>>> def func(**kwargs):
...     kwargs['hi'] = 'mom'
... 
>>> func(**mydict)
>>> print mydict
{'foo': 'bar'}

撰写回答