Home > OS >  Communicating between 2 script using multiprocessing
Communicating between 2 script using multiprocessing

Time:01-03

I'm the beginner in using multiprocessing.

Background information :

I currently create GUI (using tkinter ) to control robot. The robot could be control using python API. So now I want to connect GUI and the python API. My robot API is not completing, so I create simple testing code to see if the multiprocessing work ( called test.py).

Note : First I'm thinking to use threading but after testing with threading , the program function very slow. Hence , I change to multiprocessing.

What I want: The GUI had about 7 button . However, currently I only want to play with home cabliration button which under def button_home_cablirate_clicked() function. When the cabliration button press , the self.button_home_cablirate_done variable value = 1 will be send to the test.py and the value 1 will be contain under the variable named button_home_cablirate_done. If the button_home_cablirate_done equal 1 , the program test.py will print "hi".

Error : The data is not connected due to my code logic when setting up connection. However, I dont know how to fix my logic. Could you guys give me some advice?

Happy to learn and update my knowledge.

tkinter_oop.py :

import tkinter as tk
from tkinter import ttk 
import multiprocessing as multi

class graphic(tk.Tk):
    def __init__(self):
        super().__init__()
        self.reset_clock = 0
        self.check_value = 0 
        self.done = 0
        self.minute = 1 
        self.second = 0   
        self.button_home_cablirate_done = 0

        self.title('Automation Cleaning Process')
        self.geometry('1100x800 100 100')
        self.resizable(False, False)

        self.menubar = tk.Menu(self)
        filemenu = tk.Menu(self.menubar, tearoff=0)
        filemenu.add_command(label="New")
        filemenu.add_command(label="Open")
        filemenu.add_command(label="Save")
        filemenu.add_separator()
        filemenu.add_command(label="Exit", command=self.quit)
        self.menubar.add_cascade(label="File", menu=filemenu)
        
        helpmenu = tk.Menu(self.menubar, tearoff=0)
        helpmenu.add_command(label="Help Index")
        helpmenu.add_command(label="About...")
        self.menubar.add_cascade(label="Help",menu=helpmenu)

        #self.integer_variable_x_value = tk.IntVar()
        #self.integer_variable_y_value = tk.IntVar()
        #self.integer_variable_z_value = tk.IntVar() 
        #self.integer_variable_r_value = tk.IntVar() 
        #self.integer_variable_x_value.set(0)
        #self.integer_variable_y_value.set(0)
        #self.integer_variable_z_value.set(0)
        #self.integer_variable_r_value.set(0) 
        
        self.tabControl = ttk.Notebook(self) 
        self.tab_1 = ttk.Frame(self.tabControl)
        self.tab_2 = ttk.Frame(self.tabControl)
        self.tabControl.add(self.tab_2,text = 'HOME')
        self.tabControl.add(self.tab_1,text = 'Option')
        self.tabControl.pack(expand = 1, fill ="both")
        
        self.set_button()
        self.set_photo_gui()
        self.set_text_gui()
       
        self.set_timer_counter_process(self.minute,self.second)
        #self.update_output(200,300,400,500)
        self.config(menu=self.menubar)

    def set_button(self):
        self.button_home_cablirate = tk.Button (self.tab_1,text = "Home Cabliration", command = self.button_home_cablirate_clicked, width = 50 , height = 5 ) 
        self.button_home_cablirate.place(x=380,y=150)
        self.button_Automation_Process = tk.Button(self.tab_1, text='Automation Process',command=self.button_automation_clicked_clock_counting_down, width = 50 , height = 5)
        self.button_Automation_Process.place(x=380,y=300)
        self.button_Stop = tk.Button(self.tab_1, text='Stop',command=self.button_stop_clicked, width = 50 , height = 5 )
        self.button_Stop.place(x=380,y=450)
        self.button_connected = tk.Button (self.tab_2,text = "Connecting Dobot" , command=self.button_connected_clicked, width=50 , height =5 )
        self.button_connected.place(x=400,y=400)
        self.emergency_button = tk.Button(self, text='Emergency Stop ',command=self.test, width = 25 , height = 8 )
        self.emergency_button.place(x= 900,y = 50)
        self.slot_1 =  tk.Button(self.tab_2, text='2',command=self.test, width = 20 , height = 4)
        self.slot_1.place(x= 100 ,y = 250 )
        self.slot_2 =  tk.Button(self.tab_2, text='4',command=self.test, width = 20 , height = 4)
        self.slot_2.place(x= 500,y = 250)
        self.slot_3 =  tk.Button(self.tab_2, text='6',command=self.test, width = 20 , height = 4)
        self.slot_3.place(x= 850 ,y = 250)
        
        
        
    

    def button_connected_clicked(self): 
        self.connecting = tk.Label(self.tab_2,text = "Connecting ...", font=("Inter", 25))
        self.connecting.place(x = 450  , y = 350)
 

    def button_home_cablirate_clicked(self,conn): 
     self.button_home_cablirate_done = 1
     conn.send(self.button_home_cablirate_done) 
     print ("button 1 click ")
     
   
    def button_automation_clicked_clock_counting_down(self):
     self.done = 1 
     self.button_automation_done = 2
     print ("button 2 click ")
     

    def button_stop_clicked(self): 
     self.button_stop_done = 3
     print ("button 3 click")
     

     
   
    def test():
        pass
    



    def set_text_gui(self): 
        #declare label 
        self.choose_clean_slot = tk.Label(self.tab_2,text = "Please choose how many slot avaliable ", font=("Inter", 20))

        self.time_title = tk.Label(self.tab_2, text = "Time Process:", font=("Inter",30))
        self.time_colon= tk.Label(self.tab_2, text = ":", font=("Inter",  30))
        self.min_label= tk.Label(self.tab_2, text = "min", font=("Inter", 30))
        self.second_label=tk.Label(self.tab_2, text = "sec", font=("Inter",30))
        self.label_minute = tk.Label(self.tab_2,font=("Inter",30))
        self.label_second = tk.Label (self.tab_2,font=("Inter",30))
        self.label_minute_zero_add = tk.Label(self.tab_2,font=("Inter",30))
        self.label_second_zero_add = tk.Label(self.tab_2,font=("Inter",30))
        # position label 
        
        self.choose_clean_slot.place(x = 85  , y = 100)


        self.time_title.place(x=85,y=590) 
        self.time_colon.place(x =230,y=650)
        self.min_label.place(x=150,y=650)
        self.second_label.place(x=335,y=650)
        self.label_minute.place(x = 120 , y = 650)
        self.label_second.place(x=  278 , y = 650)
        self.label_minute_zero_add.place(x=  90 ,y=650)
        self.label_second_zero_add.place(x = 250 ,y= 650)
   
    #def update_output(self , input_dobot_x, input_dobot_y, input_dobot_z , input_dobot_r):
        # update x-axis 
        #self.integer_variable_x_value.set(input_dobot_x)
        #self.x_axis_value.config(text=str(self.integer_variable_x_value.get()))
        # update y axis 
        #self.integer_variable_y_value.set(input_dobot_y)
        #self.y_axis_value.config(text=str(self.integer_variable_y_value.get()))
        # update z axis 
        #self.integer_variable_z_value.set(input_dobot_z)
        #self.z_axis_value.config(text=str(self.integer_variable_z_value.get()))
        
        # update r axis
        #self.integer_variable_r_value.set(input_dobot_r)
        #self.r_axis_value.config(text=str(self.integer_variable_r_value.get()))
        
        #update all the variable every 100secs to GUI 
        #self.after(100,self.update)

    def set_timer_counter_process(self,minute,second):
        self.label_minute['text'] = minute
        self.label_second['text'] = second
        check_minute_length = len(str(minute))
        check_second_length = len(str(second))
        if check_minute_length == 1: 
            self.label_minute_zero_add['text'] = 0 
        else: 
            self.label_minute_zero_add['text'] =''

        if check_second_length == 1:
            self.label_second_zero_add['text'] = 0  
        else:
            self.label_second_zero_add['text'] ='' 

        if self.done == 1:      
            if second  > 0 :
                second = second - 1       
            elif second <= 0 :
                if minute > 0:
                    minute  = minute - 1  
                    second  = 60 
                else:
                    self.done = 0
        else:
            minute = 1
            second = 0           
        self.after(1000, self.set_timer_counter_process, minute , second) 


def run_GUI():
    
    User_graphic = graphic()
    User_graphic.mainloop()





test.py :

def check (conn): 
    print("welcome")
    button_home_cablirate_done = conn.recv()
    if (button_home_cablirate_done == 1): 
        for x in range(2):
            print ("hi")
    elif (button_home_cablirate_done ==2 ): 
        print ("no")


main.py :

import multiprocessing 
import test 
import tkinter_oop
from tkinter_oop import graphic 

def test_1(conn): 
    test.check(conn)

def GUI_Script(): 
    tkinter_oop.run_GUI
    

   
if __name__ == '__main__':
    conn1, conn2 = multiprocessing.Pipe()
    process_GUI = multiprocessing.Process(target=GUI_Script,args=(conn1,))
    process_test= multiprocessing.Process(target=test_1,args=(conn2,))
    process_GUI.start()
    process_test.start()
    process_GUI.join()
    process_test.join()             

CodePudding user response:

I guess this is what you are trying to achieve

#! /usr/bin/env python3

import multiprocessing as mp
import os

def f(conn):
    conn.send(['f', os.getpid(), 'hello'])
    conn.close()

def g(conn):
    print(['g', os.getpid(), conn.recv()])
    conn.close()

if __name__ == '__main__':
    print(f'main {os.getpid()}')
    conn1, conn2 = mp.Pipe()
    p = mp.Process(target=f, args=(conn2,))
    q = mp.Process(target=g, args=(conn1,))
    p.start()
    q.start()
    p.join()
    q.join()

which creates a pipe and 2 processes communicating over it.

When run, it prints

main 2518
['g', 2521, ['f', 2520, 'hello']]

so you can see the different pids and the message sent and received.

The problem might be in the functions you are invoking as target.

CodePudding user response:

You wrote:

def GUI_Script(): 
    tkinter_oop.run_GUI

You wanted:

def GUI_Script(): 
    tkinter_oop.run_GUI()

That is, you evaluated an expression, a function reference. But you wanted to call that function.


I change to multiprocessing.

Yes, I agree, multiple python processes often works out better than multiple threads as a first cut at understanding how to divide the tasks so as to keep many cores busy. Each new process brings a new GIL to the party, something you can't say for new threads.


Your use of the multiprocessing module seems slightly odd. Typically the motivation for using "multi" is we have a bunch of work to hand out to K interchangeable workers, and we don't really care what K is. So Pool is the central abstraction. OTOH you have a very specific number of processes, each with a distinct role.

Consider using subprocess instead. It offers a similar API for the things you're doing.

CodePudding user response:

You should not run GUI in a child thread, run it in main thread instead. Also you need to pass conn1 to tkinter_oop.run_GUI().

Updated main.py:

import multiprocessing
import test
import tkinter_oop
#from tkinter_oop import graphic

def test_1(conn):
    test.check(conn)

def GUI_Script(conn):
    # pass conn to run_GUI()
    tkinter_oop.run_GUI(conn)


if __name__ == '__main__':
    conn1, conn2 = multiprocessing.Pipe()
    process_test = multiprocessing.Process(target=test_1, args=(conn2,))
    process_test.start()
    # run GUI in main thread
    GUI_Script(conn1) # pass conn1 to GUI_Script()

Required updates in tkinter_oop.py:

...
class graphic(tk.Tk):
    def __init__(self, conn):
        ...
        self.set_button(conn) # pass conn to self.set_button()
        ....

    def set_button(self, conn):
        # pass conn to self.button_home_cablirate_clicked()
        self.button_home_cablirate = tk.Button(self.tab_1,text="Home Cabliration", command=lambda:self.button_home_cablirate_clicked(conn), width=50, height=5) 
        ...

    ...

def run_GUI(conn):
    # pass conn to graphic()
    User_graphic = graphic(conn)
    User_graphic.mainloop()
  • Related