Search code examples
pythonwhile-loopmultiprocessing

How to break an infinite loop in module from main script?


I'm trying to have a while loop in my module for a main script Python. Is there a way to do this without using multiprocessing, as I've seen that multiprocessing isn't viable in modules due to Windows not having fork support.

So I'm trying to fit the while loop inside either the start_capture or measure function, and then start the measure function as process (if needed), so that it would look either something like this:

#mainScript.py
from sensorHandler import SensorHandler
sensors = SensorHandler()
sensors.start_capture()
sensors.stop_capture()

#sensorHandler.py
class SensorHandler():
    def __init__ (self):
        self.sensors = []        

    def start_capture(self):
        process = Process(target=measure,args=(self.sensors,))
        process.start()
    
    def stop_capture():
        process.terminate()            

    def measure(sensors):
        while True:
            #do stuff

Or like this:

#mainScript.py
from sensorHandler import SensorHandler
sensors = SensorHandler()
sensors.start_capture()
sensors.stop_capture()

#sensorHandler.py
class SensorHandler():
    def __init__ (self):
        self.sensors = [] 

    def start_capture(self):
        while something:
            #do stuff

    def stop_capture():
        something = false

But the main point is that I want to break the loop from the main script when I want it to stop measuring. Any recommendations or help would be greatly appreciated.


Solution

  • Yes, you can still use multiprocessing in Windows. In general, you just need to ensure that within the main script that you are launching any statement at global scope that directly or indirectly executes a statement that creates a child process is wrapped in an if __name__ == '__main__': block. It is also advisable to place in such a block any statement at global scope that is not required for the initialization of any child process.

    But you have other issues with sensorHandler.py. First, you do not have required arguments named self in the methods stop_capture and measure. Second, self.sensors in class SensorHandler is a regular list instance (and perhaps not well-named). When the child process is created and presumably appends to this list, it is doing so to a copy of the SensorHandler instance that resides in the new address space created for the child process. So, as currently coded, there is no way for the main program to retrieve this list. One solution is to use a managed list, which is shareable across processes. But be aware that each operation on this list is slower that if you were using a regular list. So I would have the main process create the managed list and use it to instantiate the SensorHandler instance as follows:

    In your case, mainScript.py will look like:

    if __name__ == '__main__':
        from sensorHandler import SensorHandler
        from multiprocessing import Manager
    
        with Manager() as manager:
            measurements = manager.list()
            sensor_handler = SensorHandler(measurements)
            sensor_handler.start_capture()
            input('Hit enter to stop capturing... ')
            sensor_handler.stop_capture()
            print(measurements)
    

    Then I would code sensorHandler.py as follows:

    from multiprocessing import Process
    import time
    
    class SensorHandler():
        def __init__ (self, measurements):
            self.measurements = measurements
    
        def start_capture(self):
            self.process = Process(target=self.measure)
            self.process.start()
    
        def stop_capture(self):
            self.process.terminate()
    
        def measure(self):
            for i in range(100):
                self.measurements.append(i)
                time.sleep(1)
    

    Prints (when terminated after a few seconds):

    [0, 1, 2]
    

    Note that I have renamed attribute sensors to measurements since presumably you are appending to this list sensor readings or measurements and not sensors.