I'm running a multiprocessing system in Python, and I was planning to divide the terminal window in 4 quadrants, and display the output of each of the processes in one of them.
So, the final output should look something like:
----------------------------------
| | |
| PROCESS_01 | PROCESS_02 |
| | |
----------------------------------
| | |
| PROCESS_03 | PROCESS_04 |
| | |
----------------------------------
I have a main file, from where the single processes start:
if __name__ == "__main__":
set_start_method("spawn")
p01 = mp.Process(target=p01_Initializer, args=(...))
p01.daemon = True
p01.start()
p02 = mp.Process(target=p02_Initializer, args=(...))
p02.daemon = True
p02.start()
p03 = mp.Process(target=p03_Initializer, args=(...))
p03.daemon = True
p03.start()
p04 = mp.Process(target=p04_Initializer, args=(...))
p04.daemon = True
p04.start()
and I was planning to use the curses module to achieve this visualization.
Basically in each process I created a different window. Both have the same height/width (rows_mid, cols_mid), but the idea is that the window for process 01 should originate at (0,0), while the one for process02 at coordinates (0, cols_mid), like this:
PROCESS_01
curses.initscr()
cols_tot = curses.COLS
rows_tot = curses.LINES
x_mid = int(0.5*cols_tot)
y_mid = int(0.5*rows_tot)
self.win = curses.newwin(y_mid, x_mid, 0, 0)
self.win.addstr(0, 0, "*** PROCESS 01 ***")
self.win. addstr(whatever)
PROCESS_02
curses.initscr()
cols_tot = curses.COLS
rows_tot = curses.LINES
x_mid = int(0.5*cols_tot)
y_mid = int(0.5*rows_tot)
self.win = curses.newwin(y_mid, x_mid, 0, x_mid)
self.win.addstr(0, 0, "*** PROCESS 02 ***")
self.win. addstr(whatever)
But it's not really working. At the beginning, only the output of PROCESS_02 is visualized, in the correct position. Then, only PROCESS_01 appears, but some of the stuff is visualized in the space where the output from PROCESS_02 is supposed to be, like this
Can I fix it somehow? Is there a better/easier alternative to using curses?
As mentioned in the comments:
I could obtain the same result in a simpler way by writing the output to log files and using tmux;
In case one wanted to stick to the 'manual' approach, the problem seems to be that the various processes are interfering with each other, so the screen gets overwritten by each of them.
I solved it by collecting all the output of each process in an array, which is then sent back to the main process through queues and printed there.
PROCESS_01
output_messages_01 = []
output_messages_01.append('first output of P01')
output_messages_01.append('second output of P01')
....
## limiting overall number of messages in the array (if too many, it gets out of the window row limit when printing them in terminal)
if len(output_messages_01)>15:
output_messages_01 = output_messages_01[-15:]
output_queue_p01.put((output_messages_01))
PROCESS_02
output_messages_02 = []
output_messages_02.append('first output of P02')
output_messages_02.append('second output of P02')
....
if len(output_messages_02)>15:
output_messages_02 = output_messages_02[-15:]
output_queue_p02.put((output_messages_02))
and, in the main process, I colllect and print everything
MAIN PROCESS
## creating panels
win11 = curses.newwin(rows_mid, cols_mid, 0, 0)
win12 = curses.newwin(rows_mid, cols_mid, 0, cols_mid)
win21 = curses.newwin(rows_mid, cols_mid, rows_mid, 0)
win22 = curses.newwin(rows_mid, cols_mid, rows_mid, cols_mid)
win11.addstr(0, 0, "*** PROCESS 01 ***", curses.A_BOLD)
win12.addstr(0, 0, "*** PROCESS 02 ***", curses.A_BOLD)
win21.addstr(0, 0, "*** PROCESS 03 ***", curses.A_BOLD)
win22.addstr(0, 0, "*** PROCESS 04 ***", curses.A_BOLD)
## getting array with output message from process01
p01_messages = output_queue_p01.get()
for row, message in enumerate(p01_messages):
win11.addstr(row, 0, message)
win11.clrtoeol()
## getting array with output message from process02
p02_messages = output_queue_p02.get()
for row, message in enumerate(p02_messages):
win12.addstr(row, 0, message)
win12.clrtoeol()
## same thing for processes 03 and 04 ...
win11.refresh()
win12.refresh()
win21.refresh()
win22.refresh()
and similarly for the other processes