Python中线程之间的通信(不使用全局变量)

时间:2013-05-21 18:50:46

标签: python multithreading

假设我们有一个主线程为测试模块启动两个线程 - “test_a”和“test_b”。 两个测试模块线程都保持其状态,无论它们是否已完成执行测试,或者是否遇到任何错误,警告或是否要更新其他信息。

主线程如何访问此信息并采取相应措施。 例如,如果“test_a”引发了错误标志; “main”如何知道并在出现错误之前停止其余的测试?

这样做的一种方法是使用全局变量,但这很难看。很快。

1 个答案:

答案 0 :(得分:5)

显而易见的解决方案是通过将它传递给构造函数/ start中的线程对象/函数来共享某种可变变量。

这样做的干净方法是使用适当的实例属性构建一个类。如果你使用的是threading.Thread subclass,而不仅仅是一个线程函数,你通常可以使用子类本身作为粘贴这些属性的地方。但我会用list显示它只是因为它更短:

def test_a_func(thread_state):
    # ...
    thread_state[0] = my_error_state
    # ...

def main_thread():
    test_states = [None]
    test_a = threading.Thread(target=test_a_func, args=(test_states,))
    test_a.start()

您可以(通常也希望)将LockCondition打包到可变状态对象中,这样您就可以在main_threadtest_a之间正确同步。 / p>

(另一种选择是使用queue.Queueos.pipe等来传递信息,但是你仍然需要将该队列或管道传递给子线程 - 你在与上面完全相同。)


然而,值得考虑的是你是否真的需要这样做。如果您将test_atest_b视为“作业”,而不是“线程函数”,则可以只在池上执行这些作业,并让池处理传递结果或错误。

例如:

try:
    with concurrent.futures.ThreadPoolExecutor(workers=2) as executor:
        tests = [executor.submit(job) for job in (test_a, test_b)]
        for test in concurrent.futures.as_completed(tests):
            result = test.result()
except Exception as e:
    # do stuff

现在,如果test_a函数引发异常,主线程将获得该异常 - 因为这意味着退出with块,并且所有其他作业都被取消并丢弃,并且工作线程关闭。

如果您使用的是2.5-3.1,则内置concurrent.futures,但可以安装the backport off PyPI,或者可以重写multiprocessing.dummy.Pool周围的内容。 (这是稍微那么复杂,因为你必须创建一系列作业并调用map_async来取回AsyncResult对象上的迭代器......但实际上这仍然很简单。)