无法使用多处理更新类变量

Tip*_*kek 4 python user-interface multiprocessing

我正在制作一个 GUI 应用程序来跟踪每个前台窗口所花费的时间。我尝试对每个被监视的进程进行循环来执行此操作:

class processes(object):
    def __init__(self, name, pid):
        self.name = name
        self.pid = pid
        self.time_spent = 0
        self.time_active = 0
        p1 = multiprocessing.Process(target=self.loop, args=())
        p1.start()

    def loop(self):
        t = 0
        start_time = time.time()

        while True:

            #While the process is running, check if foreground window (window currently being used) is the same as the process

            h_wnd = user32.GetForegroundWindow()
            pid = wintypes.DWORD()
            user32.GetWindowThreadProcessId(h_wnd, ctypes.byref(pid))
            p = psutil.Process(pid.value)

            name = str(p.name())
            name2 = str(self.name)

            if name2 == name:
                t = time.time() - start_time

            #Log the total time the user spent using the window
            self.time_active += t
            self.time_spent = time.perf_counter()
            time.sleep(2)

    def get_time(self):
        print("{:.2f}".format(self.time_active) + " name: " + self.name)
Run Code Online (Sandbox Code Playgroud)

我在 GUI 中选择所需的进程,并通过其名称在列表中找到它。一旦找到,我就调用函数 get_time() ,该函数应该打印所选进程在前台运行的时间。

def display_time(Lb2):
    for s in Lb2.curselection():
        for e in process_list:
            if Lb2.get(s) == e.name:
                e.get_time()
Run Code Online (Sandbox Code Playgroud)

问题是每次打印时time_active都是0。

我已经调试了该程序,并且可以看出它在某种程度上工作(并不完美,当程序不在前台时它仍然记录时间)并更新循环内的变量。但是,当打印出来时,该值仍为 0。我认为我在理解多处理方面遇到了困难,如果有人可以消除困惑的话

Boo*_*boo 5

@TheLizzard 提供了最简单的解决方案,即仅使用线程而不是多处理:

import threading
...
        #p1 = multiprocessing.Process(target=self.loop, args=())
        p1 = threading.Thread(target=self.loop, args=())
Run Code Online (Sandbox Code Playgroud)

但这并不能解释为什么创建一个流程却不起作用。发生的情况是,您的process.__init__代码首先创建了几个属性,例如self.time_activeself.time_spent等。该代码在主进程中执行。但是当你执行下面两条语句时......

        p1 = multiprocessing.Process(target=self.loop, args=())
        p1.start()
Run Code Online (Sandbox Code Playgroud)

...process创建的对象现在必须序列化/反序列化到新的地址空间Process,您刚刚创建的新实例必须在其中运行。因此,在loop方法中,当您执行诸如 之类的语句时,您正在更新子进程地址空间中“生存”self.time_active += t的实例。self.time_active但是打印出 的值的代码self.time_active是在主进程的地址空间中执行的,因此仅打印出该属性的原始值。

如果您必须使用多处理,因为您的loop方法是 CPU 密集型的,并且需要与其他进程并行,那么解决方案是在共享内存中创建self.time_active和,self.time_spent以便主进程和子进程都可以访问相同的内存,共享属性:

class processes(object):
    def __init__(self, name, pid):
        self.name = name
        self.pid = pid
        # Create shared floating point values:
        self.time_spent = multiprocessing.Value('f', 0)
        self.time_active = multiprocessing.Value('f', 0)
        ...

    def loop(self):
        ...
        self.time_active.value += t
        self.time_spent.value = time.perf_counter()
        ...

    def get_time(self):
        print("{:.2f}".format(self.time_active.value) + " name: " + self.name)

Run Code Online (Sandbox Code Playgroud)