Python-如何从打印信息的单独过程中实时读取类实例

时间:2018-11-29 14:05:11

标签: python object process multiprocessing ipc

我有一段代码正在不断创建Car类的新实例。这样,Car类将创建其自身的实例列表,因此,当我想获取当前实例的信息时,可以轻松地做到这一点,就像下面的代码一样:

from multiprocessing import Process
import time
class Car:

    car_list = list()
    def __init__(self, id, model):
        self.id = id
        self.model = model
        Car.car_list.append(self)

    @classmethod
    def get_current_instances(cls):
        return Car.car_list


class Interface:

    def print_current_system(self):
        while True:
            print(len(Car.get_current_instances()))
            time.sleep(1)



if __name__ == "__main__":

    interface = Interface()
    model = ["Toyota", "BMW"]

    [Car(i, model[i]) for i in range(len(model))]

    print_process = Process(target=interface.print_current_system)
    print_process.start()

    Car(2345, "Tesla")
    print("from main process " + str(len(Car.get_current_instances()))) 

出于问题的目的,此代码已简化。但是,问题仍然存在。我正在从新进程中调用函数print_current_system。此功能会不断查看Car的所有当前实例并打印汽车的数量。

当我开始此过程,然后再添加一些Car的新实例时,这些实例对其他子进程隐藏,而对主进程完全可见。我很确定我需要使用Queue或Pipe之类的东西。但是,我不确定如何。 这是上面代码的输出:

2
from main process 3
2
2
2
2
2

2 个答案:

答案 0 :(得分:0)

背景:由于Python本质上是单线程的(解释器由GIL或全局解释器锁保护),因此其中没有真正的线程。相反,要获得相同的效果,您必须像在示例中那样使用不同的过程。由于这些是不同的进程,具有不同的解释器和不同的命名空间,因此您将无法从另一个进程访问一个进程中的普通数据。当您创建新进程时,python解释器会派生自己,并复制所有Python对象,因此Car.car_list现在是两个不同的对象,每个进程中一个。因此,当一个进程添加到该列表时,它会添加到另一个进程正在读取的列表中。

答案:您的直觉是正确的:您将要使用多处理模块中的一种数据结构。这些数据结构被专门编写为“线程安全”(在这种情况下,我想实际上是“进程安全”),并在后台隐藏两个进程之间的共享数据。

示例:您可以使用全局队列,在该队列中,“生产者”过程将添加项目,而“消费者”过程将其删除并将其添加到其自己的列表副本中。

from multiprocessing import Queue

class Car:

    global_queue = Queue()
    _car_list = [] # This member will be up-to-date in the producer
                   # process. In that process, access it directly.
                   # In the consumer process, call get_car_list instead.
                   # This can be wrapped in an interface which knows
                   # which process it is in, so the calling code does
                   # not have to keep track.

    def __init__(self, id, model):
        self.id = id
        self.model = model
        self.global_queue.put(self)
        self._car_list.append(self)

    @classmethod
    def get_car_list(cls):
        """ Get the car list for the consumer process

            Note: do not call this from the producer process
        """
        # Before returning the car list, pull all pending cars off the queue
        # while cls.global_queue.qsize() > 0:
        # qsize is not implemented on some unix systems
        while not cls.global_queue.empty():
            cls._car_list.append(cls.global_queue.get())
        return cls._car_list

注意:使用上面的代码,您只能有一个数据使用者。如果其他进程调用get_car_list方法,则它们将从队列中删除挂起的汽车,而消费者进程将不会收到它们。如果需要多个消费者流程,则需要采用其他方法。

答案 1 :(得分:0)

如果您只想统计自己拥有多少辆汽车,可以使用Value之类的共享内存对象。

只需对代码进行一些更改即可实现所需的内容:

from multiprocessing import Process, Value
import time

class Car:

    car_list = list()
    car_quantity = Value('i', 0)     # Use a shared memory object here.

    def __init__(self, id, model):
        self.id = id
        self.model = model
        Car.car_list.append(self)
        Car.car_quantity.value += 1  # Update quantity

    @classmethod
    def get_current_instances(cls):
        return Car.car_list


class Interface:

    def print_current_system(self):
        while True:
            print(Car.car_quantity.value)  # Just print the value of the memory shared object (Value).
            time.sleep(1)



if __name__ == "__main__":

    interface = Interface()
    model = ["Toyota", "BMW"]

    [Car(i, model[i]) for i in range(len(model))]

    print_process = Process(target=interface.print_current_system)
    print_process.start()

    time.sleep(3)   # Added here in order you can see the 
                    # ouptut changing from 2 to 3.

    Car(2345, "Tesla")
    print("from main process " + str(len(Car.get_current_instances()))) 

输出:

2
2
2
from main process 3
3
3
3
3
3