在不同线程中的类之间传递变量?

时间:2018-04-30 22:03:15

标签: python multithreading class parameter-passing

假设我有两个使用线程的类

class foo(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self,name="foo=>bar")
        self.var1 = {}

    def run(self):
        while True
            value, name = getvalue()  // name is an string
            self.var1[name] = value
            bar(self)


class bar(threading.Thread):
    def __init__(self,fooInstance):
        threading.Thread.__init__(self,name="bar")

    def run(self):
        while True
            arg = myfunction()  // somefunction (not shown for simplicity)
            val = myOtherfunction(fooInstance.var1[arg])  //other function
            print(val)


f = foo()
f.start()

var1中的变量foo会随着时间的推移而发生变化,bar需要了解这些变化。这对我来说很有意义,但我想知道这里有什么根本可能最终失败的东西。这在python中是正确的吗?

2 个答案:

答案 0 :(得分:0)

实际的共享部分与“我如何与另一个对象共享一个值?”的问题相同。没有线程,所有相同的解决方案都可以工作。

例如。您已将foo实例传递到bar初始化程序,因此只需从那里获取:

class bar(threading.Thread):
    def __init__(self,fooInstance):
        threading.Thread.__init__(self,name="bar")
        self.var1 = fooInstance.var1

但这是线程安全吗?

嗯,是的,但只是因为你从未真正开始后台线程。但我假设在您的实际代码中,您将同时运行两个线程,两者都访问var1值。在这种情况下,如果没有某种同步,它就不是线程安全的。例如:

class foo(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self,name="foo=>bar")
        self.var1 = {}
        self.var1lock = threading.Lock()

class bar(threading.Thread):
    def __init__(self,fooInstance):
        threading.Thread.__init__(self,name="bar")
        self.var1 = fooInstance.var1
        self.var1lock = fooInstance.var1lock

现在,而不是这个:

self.var1[name] = value

...你这样做:

with self.var1lock:
    self.var1[name] = value

同样,而不是:

val = myOtherfunction(fooInstance.var1[arg])  //other function

...你这样做:

with self.var1lock:
    var1arg = var1[arg]
val = myOtherfunction(var1arg)

或者......事实证明,在CPython中,更新dict中的单个键的值(只有内置dict,而不是子类或自定义映射类!)一直是原子的,可能总是将会。如果你想依靠这个事实,你可以。但是,如果锁定是一个重要的性能问题,我只会这样做。我也会评论它的每一个用途,以表明它。

如果你宁愿传递值而非分享,那么通常的答案是queue.Queue或其中一位亲戚。

但这需要重新设计你的程序。例如,您可能希望在队列中传递每个新的/更改的键值对。这将是这样的:

class foo(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self,name="foo=>bar")
        self.var1 = {}
        self.q = queue.Queue()
    def run(self):
        b = bar(self)
        b.start()
        while True:
            value, name = getvalue()  // name is an string
            self.var1[name] = value
            self.q.put((name, value))
class bar(threading.Thread):
    def __init__(self,fooInstance):
        threading.Thread.__init__(self,name="bar")
        self.var1 = copy.deepcopy(fooInstance.var1)
        self.q = fooInstance.q
    def _checkq(self):
        while True:
            try:
                key, val = self.q.get_nowait()
            except queue.Empty:
                break
            else:
                self.var1[key] = val
    def run(self):
        while True:
            self._checkq()
            arg = myfunction()  // somefunction (not shown for simplicity)
            val = myOtherfunction(fooInstance.var1[arg])  //other function
            print(val)

答案 1 :(得分:-1)

虽然效率非常低,当然也不是最常用的方法,您可以使用文件传输数据。一个线程将数据写入文件,例如作为json字符串,另一个线程读取它。