【问题标题】:Passing variables between classes in different threads?在不同线程的类之间传递变量?
【发布时间】:2018-10-11 00:57:26
【问题描述】:

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

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()

foo 中的变量var1 会随着时间而变化,bar 需要注意这些变化。这对我来说很有意义,但我想知道这里是否有一些基本的东西最终可能会失败。这在 python 中正确吗?

【问题讨论】:

  • 您的代码过于简单,无法正常工作。它有(太多)问题。请edit您的问题并提供一个最小的可运行示例或更接近的示例。
  • 一般来说,在并发编程中,您经常需要使用LockSemaphore 之类的东西来确定在任何给定时间只有一个线程/进程可以访问共享资源。在这种情况下,fooInstance 可能需要它。
  • 如果您想明确传递数据而不是共享数据,通常的答案是queue.Queue(或其变体之一)。
  • 也许将var1 设为模块级字典并在 foo 更改它时使用锁。它是否需要对实例是唯一的?
  • 如果你想共享数据:有一组特定的操作在 CPython 中一直是原子的,并且可能永远都是原子的,即使它们不能保证——包括更新单个内置 dict 的键值。但无论如何我都会使用锁,除非它会导致性能问题。

标签: python multithreading class parameter-passing


【解决方案1】:

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

例如。您已经将 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)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-04-03
    • 2021-06-18
    • 2018-09-16
    • 1970-01-01
    • 1970-01-01
    • 2017-11-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多