简体   繁体   English

如何在不获取新 PID 的情况下从 multiprocessing.Process 调用主进程中的方法?

[英]how to call method in the main process from a multiprocessing.Process without getting a new PID?

I'm working in a python app where the user should be able to enter a query and get a list of results from an api.我在 python 应用程序中工作,用户应该能够输入查询并从 api 获取结果列表。 Both input and results should happen in a gui.输入和结果都应该在 gui 中发生。

This should happen as the user types (with some debounce in the future), so the user should be able to query for "foo" and a call to the api should be triggered, but if the user changes his mind and now wants to query "bar", he should be able to change his query whether the previous api call ended or not.这应该在用户键入时发生(将来会出现一些反跳),因此用户应该能够查询“foo”并且应该触发对 api 的调用,但是如果用户改变主意并且现在想要查询“bar”,他应该能够更改他的查询之前的 api 调用是否结束。

I was able to get It working synchronously, where the api call blocks the entire app until It's finished.我能够让它同步工作,其中 api 调用会阻止整个应用程序,直到它完成。 I did It like this (simplified):我这样做了(简化):

class Api:
    def get_results(self, query):
        return self.api.results(query)
    ...


class App:
    def __init__(self):
        self.gui = None
        self.api = None

    def get_results(self, query):
        self.api = Api()
        results = self.api.get_results
        self.gui.render(results)
    ...


class Gui(tk.Frame):
    def __init__(self, root, app, *args, **kwargs):
        tk.Frame.__init__(self, root, *args, **kwargs)
        self.root = root
        self.root.attributes('-type', 'dialog')
        self.app = app
        self.app.gui = self

    def render(self, results)
        # render results

In order to get It working asynchronously, I figured I should run the call in a separate thread or process and then kill It and spawn a new one every time the user changes the query in the gui.为了让它异步工作,我想我应该在一个单独的线程或进程中运行调用,然后每次用户在 gui 中更改查询时杀死它并产生一个新的。 So I changed my Api class to inherit from multiprocessing.Process , initializing It with a reference to the app instance and adding a method to run a callback in the app instance that initialized It.因此,我将 Api class 更改为从multiprocessing.Process继承,使用对应用程序实例的引用来初始化它,并添加一个方法来在初始化它的应用程序实例中运行回调。 It's a little like this:有点像这样:

class Api(multiprocessing.Process):
    def __init__(self, app, query, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.app = app
        self.query = query
        self.start()

    def get_results(self, query):
        return self.api.results(query)
    
    def run(self):
        results = self.get_results
        self.app.callback(results)


class App:
    def __init__(self):
        self.gui = None
        self.api = None

    def get_results(self, query):
        if self.api:
            self.api.kill()
        self.api = Api(self, query)
    
    def callback(self, results):
        self.gui.render(results)


class Gui(tk.Frame):
    def __init__(self, root, app, *args, **kwargs):
        tk.Frame.__init__(self, root, *args, **kwargs)
        self.root = root
        self.root.attributes('-type', 'dialog')
        self.app = app
        self.app.gui = self

    def render(self, results)
        # render results

If I run this code with some print statements, I can see that It does work properly, calling the callback with the correct values, but the gui isn't updated for some reason.如果我使用一些打印语句运行此代码,我可以看到它确实工作正常,使用正确的值调用回调,但由于某种原因没有更新 gui。 After some debugging I verified that the PIDs of the running code change.经过一些调试,我验证了运行代码的 PID 发生了变化。 The gui PID changes and the app PID changes as well once the callback function is called, so I believe that It's sort of working, but I don't know to approach this problem.一旦回调 function 被调用,gui PID 和应用程序 PID 也会发生变化,所以我相信它有点工作,但我不知道解决这个问题。

Judging by the time that I'm trying to solve this problem I believe that I'm overlooking some pretty simple way of achieving my goal here.从我试图解决这个问题的时间来看,我相信我忽略了一些非常简单的方法来实现我的目标。 Thanks in advance!提前致谢!

I believe that your problem is that the callback is happening on the other thread.我相信你的问题是回调发生在另一个线程上。 That other thread knows nothing about your GUI.其他线程对您的 GUI 一无所知。 All changes to the GUI need to happen on the main thread.对 GUI 的所有更改都需要在主线程上进行。

Try having Api just returning a value.尝试让 Api 只返回一个值。 Your other code needs to wait for that value to be returned, and then update the GUI.您的其他代码需要等待返回该值,然后更新 GUI。

GUIs and asynchronous code get a bit ugly. GUI 和异步代码有点难看。

I ended up having a Queue and a Thread together with the Process, so now the thread keeps getting results from the Queue while True and calling the callback if the value has changed.我最终得到了一个队列和一个线程以及进程,所以现在线程while True不断从队列中获取结果,并在值发生变化时调用回调。 Quite a journey.相当的旅程。

Not an elegant solution, but solved my problems for now.不是一个优雅的解决方案,但现在解决了我的问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM