Skip to main content
 首页 » 编程设计

Python、多处理和 GUI

2024年08月27日29zdz8207

我有一个带有 GUI 的程序需要进行一些多处理。这样做的目的是避免卡住 GUI,并允许用户在进程运行时使用其他一些按钮。

然后我想定义如下方法:

def start_waiting(self, parent, func, args): 
 
    self.window_waiting.show() 
 
    task=Process(func(*args)) 
    task.start() 
 
    task.join() 
 
    # Some code to execute at the end of the process 
    # 
    #... 

问题是 join() 不工作,我需要它,因为在 join() 之后执行的代码指示 Process 已经结束。我将使用该代码更新 window_waiting 的取消按钮。

然后我想到了另一种避免使用 join() 的解决方案,我将其替换为:

while task.is_alive(): 
    time.sleep(0.5) 

但是还是不行,所以我尝试了方案C,就是创建一个队列:

def worker(input, output): 
    for func, args in iter(input.get, 'STOP'): 
        result=func(*args) 
        output.put(result) 
 
 
task_queue = Queue() 
done_queue = Queue() 
task_queue.put(task) 
 
Process(target=worker, args=(task_queue, done_queue)).start() 
done_queue.get() 

最后的代码给了我错误:'Pickling an AuthenticationString object is ' TypeError:出于安全原因,不允许 Pickling AuthenticationString 对象

这让我找到了 multiprocessing.Process subclass using shared queue但我还没有设法解决问题:/

请您参考如下方法:

您的第一个示例应如下所示:

def start_waiting(self,parent,func,args): 
 
    ...not relevant code.. 
 
    self.window_waiting.show() 
 
 
    task=Process(target=func, args=args)  # This line is different. 
    task.start() 
 
 
    task.join() 

按照您的方式,它实际上并不是在子进程中执行 func;它在父进程中执行它,然后将返回值传递给 Process。当您调用 task.start() 时,它可能会立即失败,因为您传递的是 func 返回的任何内容,而不是函数对象。

请注意,因为您在 start_waiting 中调用 task.join(),它可能会阻塞您的 GUI,因为 start_waiting 赢了'返回直到 func 完成,即使它在子进程中运行。它不会阻塞的唯一方法是,如果您在与 GUI 事件循环不同的线程中运行 start_waiting。您可能想要更像这样的东西:

def start_waiting(self,parent,func,args): 
 
    ...not relevant code.. 
 
    self.window_waiting.show() # You should interact with the GUI in the main thread only. 
 
    self.task = Process(target=func, args=args)  # This line is different. 
    self.thrd = threading.Thread(target=self.start_and_wait_for_task) 
    self.thrd.start() 
 
 
def start_and_wait_for_task(self): 
    """ This runs in its own thread, so it won't block the GUI. """ 
    self.task.start() 
    self.task.join() 
    # If you need to update the GUI at all here, use GLib.idle_add (see https://wiki.gnome.org/Projects/PyGObject/Threading) 
    # This is required to safely update the GUI from outside the main thread.