【问题标题】:Problem with multiple threads call in PythonPython中多线程调用的问题
【发布时间】:2021-08-06 13:07:43
【问题描述】:

我有一个脚本,它有两个线程,一个运行这个目标函数的工作线程:

def worker_thread_function():
    print(f'Worker thread started.')
    while self._keep_running:
        try:
            task = worker_queue.get(timeout=5)
            task() # I expect to be callables.
            worker_queue.task_done() # See https://docs.python.org/3/library/queue.html
        except queue.Empty:
            continue
    print(f'Worker thread finished.')

其中worker_queue 是一个全局对象,其他“管理线程”将必须完成的工作放入其中。另一个线程以这种方式定期将内容放入此队列中:

def other_thread_function():
    while True:
        time.sleep(1)
        for device_name in devices_df.index: # Initialize this by logging once each device.
            if has_to_be_logged(device_name):
                print(f'Now queueing for log {device_name}')
                worker_queue.put(lambda: log_single_device_standby_IV(device_name))

并且函数log_single_device_standby_IV 使用该设备名称进行处理。我面临的问题是device_name 在排队任务时有正确的值,但在任务完成时有错误的值。如果我像这样在log_single_device_standby_IV 中打印:

def log_single_device_standby_IV(device_name)
    print(f'log_single_device_standby_IV({device_name})')
    # do the stuff...

在我的输出中我看到了这个:

Now queueing for log num5
log_single_device_standby_IV(num7) was called.
Now queueing for log num11
log_single_device_standby_IV(num7) was called.
Now queueing for log num5
log_single_device_standby_IV(num7) was called.

即它以某种方式将device_name 的任何值更改为num7。设备num7 随便是devices_df.index 中的最后一个,不知道这是否可以提供任何提示。如果我像这样对设备名称进行硬编码:

def other_thread_function():
    while True:
        time.sleep(1)
        for device_name in devices_df.index: # Initialize this by logging once each device.
            if has_to_be_logged(device_name):
                worker_queue.put(lambda: log_single_device_standby_IV('num4'))

它工作正常,即它使用num4 作为设备名称。

这里有什么问题?我不知道这是否与多线程有关,与 lambda 函数有关,还是什么...

【问题讨论】:

    标签: python multithreading lambda


    【解决方案1】:

    这看起来像late-binding closures 跨线程。您应该可以使用functools.partial 更正它。

    代替:

    worker_queue.put(lambda: log_single_device_standby_IV(device_name))
    

    使用

    worker_queue.put(functools.partial(log_single_device_standby_IV, device_name))
    

    【讨论】:

      【解决方案2】:

      在问了这个问题并花了相当多的时间认为这是一个与线程相关的问题之后,我发现问题出在 lambda 函数上。将带有 lambda 函数的行更改为

      worker_queue.put(lambda dev=device_name: self.log_single_device_standby_IV(dev))
      

      解决问题。

      所以问题在于 lambda 函数存储的不是device_name 的值,而是对它的引用。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2022-08-09
        • 2015-11-04
        • 2023-03-08
        • 2013-04-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多