3

I have this simple python script called myMain.py to execute another python program automatically with incremental number, and I'm running it on CentOS 7:

#!/usr/bin/python

import os
import sys
import time

def main():
    step_indicator = ""
    arrow = ">"
    step = 2
    try:
        for i in range(0,360, step):
            step_percentage = float(i)/360.0 * 100
            if i % 10 == 0:
                step_indicator += "="
            os.system("python myParsePDB.py -i BP1.pdb -c 1 -s %s" % step)
            print("step_percentage%s%s%.2f" % (step_indicator,arrow,step_percentage)+"%")
    except KeyboardInterrupt:
        print("Stop me!")
        sys.exit(0)


if __name__ == "__main__":
    main()

For now I only know this script is single thread safe, but I can't terminate it with Ctrl+C keyboard interruption.

I have read some relative questions: such as Cannot kill Python script with Ctrl-C and Stopping python using ctrl+c I realized that Ctrl+Z does not kill the process, it only pauses the process and keep the process in background. Ctrl+Break does work for my case either, I think it only terminates my main thread but keeps the child process.

I also noticed that calling os.system() will spawn a child process from the current executing process. At the same time, I also have os file I/O functions and os.system("rm -rf legacy/*") will be invoked in myParsePDB.py which means this myParsePDB.py child process will spawn child process as well. Then, if I want to catch Ctrl+C in myMain.py, should I daemon only myMain.py or should I daemon each process when they spawn?

Community
  • 1
  • 1
RandomEli
  • 1,527
  • 5
  • 30
  • 53
  • is it necessary to run `myParsePDB` in a subprocess? couldn't you just write it as a normal module with functions you can call from this script instead of using `os.system`? You should be able to do `rm` functionality with [`shutil.rmtree`](https://docs.python.org/3/library/shutil.html#shutil.rmtree) – Tadhg McDonald-Jensen Apr 13 '17 at 18:25
  • @TadhgMcDonald-Jensen It is necessary to run `myParsePDB`. `rm` is just a tiny part in `myParsePDB`. – RandomEli Apr 13 '17 at 19:01

1 Answers1

1

This is a general problem that could raise when dealing with signal handling. Python signal is not an exception, it's a wrapper of operating system signal. Therefore, signal processing in python depends on operating system, hardware and many conditions. However, how to deal with these problem is similar.

According to this tutorial, I'll quote the following paragraphs: signal – Receive notification of asynchronous system events

Signals are an operating system feature that provide a means of notifying your program of an event, and having it handled asynchronously. They can be generated by the system itself, or sent from one process to another. Since signals interrupt the regular flow of your program, it is possible that some operations (especially I/O) may produce error if a signal is received in the middle.

Signals are identified by integers and are defined in the operating system C headers. Python exposes the signals appropriate for the platform as symbols in the signal module. For the examples below, I will use SIGINT and SIGUSR1. Both are typically defined for all Unix and Unix-like systems.

In my code:

os.system("python myParsePDB.py -i BP1.pdb -c 1 -s %s" % step) inside the for loop will be executed for a bit of time and will spend some time on I/O files. If the keyboard interrupt is passing too fast and do not catch asynchronously after writing files, the signal might be blocked in operating system, so my execution will still remain the try clause for loop. (Errors detected during execution are called exceptions and are not unconditionally fatal: Python Errors and Exceptions).

Therefore the simplest way to make them asynchonous is wait:

try:
    for i in range(0,360, step):
        os.system("python myParsePDB.py -i BP1.pdb -c 1 -s %s" % step)
        time.sleep(0.2)
except KeyboardInterrupt:
    print("Stop me!")
    sys.exit(0)

It might hurt performance but it guaranteed that the signal can be caught after waiting the execution of os.system(). You might also want to use other sync/async functions to solve the problem if better performance is required.

For more unix signal reference, please also look at: Linux Signal Manpage

RandomEli
  • 1,527
  • 5
  • 30
  • 53
  • When you say « It might hurt performance », do you mean the performance of the python script, of the subprocess or both? I want to know if this will slow down GPU benchmarks launched through these calls. – Dimitri Lesnoff Jul 06 '23 at 08:39