A decorator to restrict the execution time of Python features
On this article, I’ll stroll you thru making a decorator to restrict the execution time of a perform in your Python program through multiprocessing. My major motivation for constructing this decorator was to restrict a Python features execution time with a easy syntax and minimal dependencies.
A naive strategy is to make use of a timer contained in the Python perform, periodically verify if the executing Python perform had exceeded that restrict, after which exit. That strategy could also be okay for a easy one-off resolution, however any name to a third-party library would stop checking the time restrict.
I additionally wished an answer that was as unobtrusive as attainable and may very well be utilized simply all through the codebase. Decorators present the great syntax and abstraction to perform this objective.
With that in thoughts, I knew I wished to create a decorator that may very well be hooked up to any perform in my venture. The decorator would deal with limiting the perform’s execution time to some specified quantity. I additionally wished to maintain the whole lot purely in Python to restrict the dependencies/complexity of including this type of scheduler.
The primary challenges of doing this had been
- The decorator ought to take a parameter for the max execution time to make it simply extensible.
- The embellished features are in a position to have arbitrary inputs/outputs.
- The timer ought to work even when the executing perform made calls to third-party libraries.
To begin, I wanted to create a decorator that would take parameters as arguments. After some analysis, I discovered a wonderful stack overflow thread the place individuals proposed a number of options.
I adopted the structure given in a put up by Peter Mortensen within the feedback to create a decorator for decorators. I gained’t go into how this works, however you possibly can bounce into the thread for a extra detailed clarification. For extra details about decorators, I typically go right here for a refresher.
You possibly can then connect this decorator to the decorator you wish to apply to your perform, permitting you to parameterize that decorator. I wish to create a run_with_timer decorator that takes the utmost execution time as a parameter. It seems like this.
Subsequent, we are able to fill within the code to restrict execution time. The logic is as follows; the principle course of will use Python’s multiprocessing to run the embellished perform in a separate course of. The primary course of will set a timer and kill the subprocess executing the perform if it exceeds the timer.
The code for establishing the multiprocessing is two-part. The primary is a perform I name function_runner, which acts as a wrapper operating within the new course of to deal with operating the Python perform and returning the outcomes that the multiprocessing perform can deal with. The second is the multiprocessing code which spawns the brand new course of, units a timer, then kills the spawned course of if it hasn’t completed in time.
Lastly, I can create the perform to wrap with my run_with_timer decorator. I’ll name it sleeping bear.
Once we run the sleeping_bear perform, it’ll terminate f it exceeds the time restrict set within the decorator parameter. If the Python perform finishes earlier than the time restrict, the send_end handler returns the outcomes.
sleeping_bear("Grizzly", hibernation=10)>> Grizzly goes to hibernate
>> 0 zZZ
>> 1 zZZzZZ
>> 2 zZZzZZzZZ
>> 3 zZZzZZzZZzZZ
>> 4 zZZzZZzZZzZZzZZ
>>
>> TimeExceededException: Exceeded Execution Timesleeping_bear("Grizzly", hibernation=2)>> Grizzly goes to hibernate
>> 0 zZZ
>> 1 zZZzZZ
>>
>> "Grizzly is waking up!"
In abstract, I’ve proven you create a decorator to restrict the execution time of Python features utilizing multiprocessing as a scheduler. I used to be in a position to remedy the three primary issues.
- Create a parameterized decorator to restrict the max execution time.
- Enable arbitrary enter parameters to the Python features being wrapped.
- Restrict the execution time for any perform by benefiting from system-level schedulers within the multiprocessing module.
As a bonus, it was all completed with Python and no third-party dependencies. There may be some overhead to launching multiprocessing, however my objective was to restrict longer operating features, so this was not a deal breaker.
I hope you loved this brief snippet of labor. Thanks for studying, and as at all times, in case you have any strategies or suggestions, please let me know within the feedback.