pythonsubprocesspython-multiprocessing

Running a python script in the background, then passing an event to end it after a given amount of time


In short, I'm trying to run a python script from another python script but in the background, allowing the parent script to continue executing, and then to pass a CTRL_C_EVENT to the child script to trigger a final set of commands without abruptly terminating. Then for the parent script to repeat this operation an arbitrary number of times.

In more specifics, I'm working with an AB PLC and the intended child script was previously written to pull the values of specific tags on the PLC every x seconds and log them to an excel file. This script was originally written to be run as a stand-alone program that:

  1. Pings the PLC address to check for connection
  2. Immediately begins logging tag values every x (0.02) seconds
  3. Only stops logging after receiving a "KeyboardInterrupt" exception
  4. Following the log stop, does a final set of instructions to the logged data file (creating plots, etc.) before saving and closing the excel file

The parent script I'm currently working on is intended to automate some repeat data collection using the child script. Specifically, I'd like it to:

  1. Check the PLC address for connection like above (skipping the process in the child script)
  2. Start the child script and run it in the background (preferably silently, preventing it from opening more terminal windows), passing a string to use as the saved file name as an argument
  3. With the child script running and logging, start the first timer and send basically an 'ON' command to the PLC to start a process
  4. After the first timer finishes, send a second command to the PLC and then wait for a second timer to finish
  5. After the second timer ends, pass a 'CTRL_C_EVENT' to the child script to properly end the logging and run the final set of commands for closing as intended.
  6. Repeat steps 2-5 two more times to produce replicate data collections, sequentially naming the output file of the child script before waiting for additional user input as the machine setup is changed before the next set of data collections.

The parts of the parent script I'm having trouble with are starting the child script with arguments to run in the background, and then how to pass the 'CTRL_C_EVENT' into it to end it (or use an internal function of the logging.py child script to end the loop). At this point I can't tell whether multiprocessing or the subprocess module would be more appropriate here, or how to implement them.


Solution

  • I'd use subprocess, since multiprocessing is more suited for running one block of code multiple times in parallel (which you don't seem to be doing). subprocess also gives you more control with the process itself.

    You'll want to use subprocess.Popen, which allows you to start a process and then continue running code without waiting for the process to end on its own.

    Finally, to end the process, you want to send the SIGINT signal, which is what gets sent when you normally hit Ctrl+C.

    import signal
    
    filename = "something"
    
    process = subprocess.Popen(["python", "child_script_path.py", filename])
    
    # ...
    
    process.send_signal(signal.SIGINT)
    

    If your child script logs data to the terminal (stdout), you'll need to tell subprocess to read those logs and put them somewhere (see the Popen docs here). If the script logs to a file, you're all set.