Python多进程中子进程获取用户输入的问题及可行方案咨询
Hey there, let's work through this problem together!
The core issue here is that when using the spawn start method in multiprocessing, child processes don't inherit the parent's stdin properly, and you can't pickle file objects (like your newstdin) to pass them between processes. Let's look at two solid solutions, starting with the most reliable one.
Solution 1: Let the Main Process Handle User Input (Recommended)
Instead of trying to make the child process read stdin directly, have the child send a request to the main process, which handles the input and sends the result back. This follows multiprocessing best practices and avoids stdin-related headaches.
Here's how to adjust your code:
main.py
import multiprocessing as mp import sys from child_process_01 import Child_Process_01 from child_process_02 import Child_Process_02 if __name__ == "__main__": mp.set_start_method("spawn") c1_c2_q = mp.Queue(maxsize=1) # Add two new queues for input requests/responses input_request_q = mp.Queue() input_response_q = mp.Queue() # Start child processes c1 = mp.Process(target=Child_Process_01, args=(c1_c2_q,)) c1.daemon = True c1.start() c2 = mp.Process(target=Child_Process_02, args=(c1_c2_q, input_request_q, input_response_q)) c2.daemon = True c2.start() # Main process handles all user input requests from C2 while True: try: # Wait for a prompt from C2 prompt = input_request_q.get() usr_input = input(prompt) input_response_q.put(usr_input) except KeyboardInterrupt: # Handle Ctrl+C to exit cleanly break
child_process_02.py
import multiprocessing as mp def Child_Process_02(c1_c2_q, input_request_q, input_response_q): while True: try: message = c1_c2_q.get_nowait() except mp.Queue.Empty: message = None if message: if message == "something": # Fix: use == instead of = for comparison # Send input request to main process input_request_q.put('In this situation, I need user input: ') # Wait for the response usr_input = input_response_q.get() print(f"C2 received user input: {usr_input}")
child_process_01.py (example message producer)
import time def Child_Process_01(c1_c2_q): while True: # Simulate generating a trigger message c1_c2_q.put("something") time.sleep(3) # Send message every 3 seconds
This approach works because:
- The main process retains full access to stdin
- All communication happens via pickle-safe queues
- You avoid race conditions or platform-specific stdin issues
Solution 2: Pass the Stdin File Descriptor (Platform-Dependent)
If you really need the child process to read stdin directly, you can pass the raw file descriptor integer (instead of the TextIOWrapper object) and re-open it in the child. Note this may not work reliably on Windows, as spawn doesn't inherit file descriptors the same way as Unix-like systems.
main.py
import multiprocessing as mp import sys import os from child_process_01 import Child_Process_01 from child_process_02 import Child_Process_02 if __name__ == "__main__": mp.set_start_method("spawn") c1_c2_q = mp.Queue(maxsize=1) # Get the raw file descriptor for stdin stdin_fd = sys.stdin.fileno() c1 = mp.Process(target=Child_Process_01, args=(c1_c2_q,)) c1.daemon = True c1.start() c2 = mp.Process(target=Child_Process_02, args=(c1_c2_q, stdin_fd)) c2.daemon = True c2.start() c1.join() c2.join()
child_process_02.py
import sys import os import multiprocessing as mp def Child_Process_02(c1_c2_q, stdin_fd): # Re-open the file descriptor as stdin sys.stdin = os.fdopen(stdin_fd, 'r') while True: try: message = c1_c2_q.get_nowait() except mp.Queue.Empty: message = None if message: if message == "something": usr_input = input('In this situation, I need user input: ') print(f"C2 received user input: {usr_input}")
Final Notes
Stick with Solution 1 if you want cross-platform reliability—it's the safest way to handle user input in multiprocessing setups. Solution 2 is a workaround but may break on Windows or cause unexpected behavior if multiple processes try to read stdin at once.
内容的提问来源于stack exchange,提问作者Carlo

