5

I have a question on multiprocessing and tkinter. I am having some problems getting my process to function parallel with the tkinter GUI. I have created a simple example to practice and have been reading up to understand the basics of multiprocessing. However when applying them to tkinter, only one process runs at the time. (Using Multiprocessing module for updating Tkinter GUI) Additionally, when I added the queue to communicate between processes, (How to use multiprocessing queue in Python?), the process won't even start.

Goal: I would like to have one process that counts down and puts the values in the queue and one to update tkinter after 1 second and show me the values.

All advice is kindly appreciated

Kind regards, S

EDIT: I want the data to be available when the after method is being called. So the problem is not with the after function, but with the method being called by the after function. It will take 0.5 second to complete the calculation each time. Consequently the GUI is unresponsive for half a second, each second.

EDIT2: Corrections were made to the code based on the feedback but this code is not running yet.

class Countdown(): 
    """Countdown prior to changing the settings of the flows"""

    def __init__(self,q):

        self.master = Tk()
        self.label = Label(self.master, text="", width=10)
        self.label.pack()
        self.counting(q)

    # Countdown()
    def counting(self, q):
        try:
            self.i = q.get()
        except:
            self.label.after(1000, self.counting, q)

        if int(self.i) <= 0:
            print("Go")
            self.master.destroy()

        else:
            self.label.configure(text="%d" % self.i)
            print(i)
            self.label.after(1000, self.counting, q)

def printX(q):
    for i in range(10):
        print("test")
        q.put(9-i)
        time.sleep(1)
    return


if __name__ == '__main__':
    q = multiprocessing.Queue()

    n = multiprocessing.Process(name='Process2', target=printX, args = (q,)) 
    n.start() 

    GUI = Countdown(q)
    GUI.master.mainloop()
Community
  • 1
  • 1
Stijn Van Daele
  • 285
  • 1
  • 14
  • 1
    Using after won't make the program run slower, it will make it run faster because you won't have the overhead of processing the queue. And since your `counting` method also uses `after`, all multiprocessing does for you is add overhead and compexity. – Bryan Oakley Mar 17 '17 at 11:45
  • But i want the data to be available when the after method is being called. So the problem is not with the after function, but with the method being called by the after function. It will take 1 second to complete the calculation each time. Consequently the GUI is unresponsive for half a second, each second. – Stijn Van Daele Mar 18 '17 at 22:26
  • The GUI will present data collected by a function with is communicating with a RS232. It is this which takes time. So additionally to the 1 second because of the after, it will add some time due to value collection. It makes my GUI "freeze" each loop. – Stijn Van Daele Mar 18 '17 at 22:28
  • Ok, if your actual problem is with code that takes longer to run, you need to mention that in your question. – Bryan Oakley Mar 19 '17 at 00:21
  • I have edited the original question. – Stijn Van Daele Mar 20 '17 at 09:01
  • Your code still shows that you create the process _after_ calling `mainloop`. – Bryan Oakley Mar 20 '17 at 11:05
  • I changed my code not the post. Edit made. – Stijn Van Daele Mar 20 '17 at 13:34

3 Answers3

3

Multiprocessing does not function inside of the interactive Ipython notebook. Multiprocessing working in Python but not in iPython As an alternative you can use spyder.

Community
  • 1
  • 1
Stijn Van Daele
  • 285
  • 1
  • 14
2

No code will run after you call mainloop until the window has been destroyed. You need to start your other process before you call mainloop.

Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
2

You are calling wrong the after function. The second argument must be the name of the function to call, not a call to the function.

If you call it like

self.label.after(1000, self.counting(q))

It will call counting(q) and wait for a return value to assign as a function to call.

To assign a function with arguments the syntax is

self.label.after(1000, self.counting, q)

Also, start your second process before you create the window and call counting.

n = multiprocessing.Process(name='Process2', target=printX, args = (q,)) 
n.start() 

GUI = Countdown(q)
GUI.master.mainloop()

Also you only need to call mainloop once. Either position you have works, but you just need one


Edit: Also you need to put (9-i) in the queue to make it count down.

q.put(9-i)

Inside the printX function

Noel Segura Meraz
  • 2,265
  • 1
  • 12
  • 17
  • Dear Noel, thanks for your corrections. I overlooked the second mainloop call. I added the corrections and updated the code (&and the question) but still the code does not run. I have been trying mixing things but without success. Any further advice? – Stijn Van Daele Mar 21 '17 at 17:35
  • I have found the problem. Multiprocessing does not function inside of the ipython notebook. Thanks for your help. – Stijn Van Daele Mar 21 '17 at 22:44