As can be seen in the code below, two multiprocessing runs together, but both have a moment that can ask for an input()
in the Terminal, is there any way to pause the other multiprocessing until the answer is given in the Terminal?
File Code_One
archaic and simple example to speed up the explanation:
from time import sleep
def main():
sleep(1)
print('run')
sleep(1)
print('run')
sleep(1)
input('Please, give the number:')
File Code_Two
archaic and simple example to speed up the explanation:
from time import sleep
def main():
sleep(2)
input('Please, give the number:')
sleep(1)
print('run 2')
sleep(1)
print('run 2')
sleep(1)
print('run 2')
sleep(1)
print('run 2')
sleep(1)
print('run 2')
File Main_Code
:
import Code_One
import Code_Two
import multiprocessing
from time import sleep
def main():
while True:
pression = multiprocessing.Process(target=Code_One.main)
xgoals = multiprocessing.Process(target=Code_Two.main)
pression.start()
xgoals.start()
pression.join()
xgoals.join()
print('Done')
sleep(5)
if __name__ == '__main__':
main()
How should I proceed in this situation?
In this example, as it doesn't pause the other multi, whenever it asks for an input this error happens:
input('Please, give the number:')
EOFError: EOF when reading a line
Sure, this is possible. To do it you will need to use some sort of interprocess communication (IPC) mechanism to allow the two processes to coordinate. time.sleep
is not the best option though, and there are much more efficient ways of tackling it that are specifically made just for this problem.
Probably the most efficient way is to use a multiprocessing.Event
, like this:
import multiprocessing
import sys
import os
def Code_One(event, fno):
proc_name = multiprocessing.current_process().name
print(f'running {proc_name}')
sys.stdin = os.fdopen(fno)
val = input('give proc 1 input: ')
print(f'proc 1 got input: {val}')
event.set()
def Code_Two(event, fno):
proc_name = multiprocessing.current_process().name
print(f'running {proc_name} and waiting...')
event.wait()
sys.stdin = os.fdopen(fno)
val = input('give proc 2 input: ')
print(f'proc 2 got input {val}')
if __name__ == '__main__':
event = multiprocessing.Event()
pression = multiprocessing.Process(name='code_one', target=Code_One, args=(event, sys.stdin.fileno()))
xgoals = multiprocessing.Process(name='code_two', target=Code_Two, args=(event, sys.stdin.fileno()))
xgoals.start()
pression.start()
xgoals.join()
pression.join()
This creates the event
object, and the two subprocesses. Event objects have an internal flag that starts out False
, and can then be toggled True
by any process calling event.set()
. If a process calls event.wait()
while the flag is False
, that process will block until another process calls event.set()
.
The event
is created in the parent process, and passed to each subprocess as an argument. Code_Two
begins and calls event.wait()
, which blocks until the internal flag in the event
is set to True
. Code_One
executes immediately and then calls event.set()
, which sets event
's internal flag to True
, and allows Code_Two
to proceed. At that point both processes have returned and called join
, and the program ends.
This is a little hacky because it is also passing the stdin
file number from the parent to the child processes. That is necessary because when subprocesses are forked, those file descriptors are closed, so for a child process to read stdin
using input
it first needs to open the correct input stream (that is what sys.stdin = os.fdopen(fno)
is doing). It won't work to just send sys.stdin
to the child as another argument, because of the mechanics that Python uses to set up the environment for forked processes (sys.stdin
is a IO wrapper object and is not pickleable).