python:从单独的线程写入全局变量创建一个副本

时间:2017-01-02 12:25:14

标签: python multithreading callback

我正在尝试创建一个全局状态变量,它是用回调方法(事件处理程序)编写的。 但是,回调在另一个内存位置创建一个副本(深层),其他方法(当然)没有看到它。 这是情况

class Server:
  def __init__(self):
    self.callbacks=[]
    #create a web server instance to listen to requests
    self.app=Flask("test")

  def add_callback(self, func):
    self.calbacks.append(func)
    self.app.add_url_rule("/test", "test", self.handle_http_request)

  def handle_http_request(self):
    content = request.get_json(silent=True)
    for ca in self.callbacks:
      ca(content)

  def start_server(self):
    #some stuff starting flask here...


class SomeModule:
  def __init__(self):
    self.ws=Server()
    self.ws.add_callback(self.callback)
    self.callback_called=False

  def callback(self, content):
    print "callback executing---"
    print "var addr before callback assign: "+str(hex(id(self.callback_called)))
    self.callback_called=True
    print "var addr after callback assign: "+str(hex(id(self.callback_called)))

  def start(self):
    self.ws.start()
    #send a request to the server using the request library, which invokes all the trigger
    #check the state variable:
    print "var addr before check: "+str(hex(id(self.callback_called)))
    if (not self.callback_called):
      raise Exception("error...")

if __name__ == '__main__':
  sm=SomeModule()
  sm.start()

然后输出:

callback executing---
var addr before callback assign: 0x927910
var addr before callback assign: 0x927930
var addr before check: 0x927910

有谁能建议我如何避免这种情况? 在c ++中,它明确了如何访问指针和互斥锁。然而,在这里,我没有设法找到任何方法来对变量进行安全写入......

提前多多感谢!

2 个答案:

答案 0 :(得分:1)

由于您在标签中使用多线程而不是多处理,我仍然会继续发布此答案。可能对某些人有帮助。

有些对象是immutable,正如你所说的那样被复制了。其他变量,例如dictionaries,往往不是可以从函数或威胁中操纵(不确定线程​​是否仅适用于某些情况)。

例如,如果将dict作为参数传递给线程,则可以操纵该变量并影响变量的原始版本。

然而,这样做有风险。可能存在更新冲突,访问冲突,并且通常很难跟踪事情的发生。

但是这里有一个如何将dict传递给线程并显示更改的示例。这很粗糙,但给你一个有效的例子。

from threading import *

class server(Thread):
    def __init__(self, o):
        self.o = o
        Thread.__init__(self)
        self.start()

    def run(self):
        for i in range(3):
            self.o['test'] = i

test_var = {'test' : 0}
server(test_var)

while len(enumerate()) > 1: # Stupid and oversimplified wait for threads to end.
    pass

print(test_var)

答案 1 :(得分:0)

问题实际上是在其他地方。 :(原因是,Flask(Web服务器)是在一个单独的线程中启动的,有些实例由于某种原因被复制。我没有进一步挖掘,只是避免使用Flask并切换到cherrypy并启动它在非阻塞模式。 Thinkgs开始按预期在那里工作。

@torxed,非常感谢你的帮助。它确实指出了我正确的方向!