Reputation: 58953
In python, if I want to keep a process or thread running forever, I can typically do this with an empty while loop:
while 1:
pass
This, however, will eat an unfair amount of CPU process. Adding a short sleep
would work:
import time
while 1:
time.sleep(0.01)
Is there any best or cleaner way of doing this?
Upvotes: 19
Views: 22216
Reputation: 41710
This uses the asyncio
technique similar to the answer in https://stackoverflow.com/a/60631484/242042.
Deriving from the answer at Python asyncio: event loop does not seem to stop when stop method is called this is how I did it on my AHK mapping script
import asyncio
loop = asyncio.get_event_loop()
def stop_loop():
"""
This can be called from another thread to schedule stopping the event loop
"""
loop.call_soon_threadsafe(loop.stop)
try:
loop.run_forever()
finally:
loop.close()
The advantage to this aside from the while True: sleep
approach is it provides a more or less consistent approach to handling termination of the app not just CtrlC or an explicit condition check.
In addition instead of sleep
it uses select
internally based on the answer to my other question https://stackoverflow.com/a/78465221/242042 and per the comment of the person providing the answer select
will block without taking any resources.
Upvotes: 0
Reputation: 71
Someone might end up to this old question so I'll be leaving this here. The optimal way is a BlockingScheduler from apscheduler module with which you also get to schedule jobs in regular intervals (or cron like or whatever)
from datetime import datetime
import os
from apscheduler.schedulers.blocking import BlockingScheduler
def tick():
print('Tick! The time is: %s' % datetime.now())
if __name__ == '__main__':
scheduler = BlockingScheduler()
scheduler.add_job(tick, 'interval', seconds=3)
print('Press Ctrl+{0} to exit'.format('Break' if os.name == 'nt' else 'C'))
try:
scheduler.start()
except (KeyboardInterrupt, SystemExit):
pass
Upvotes: 1
Reputation: 30342
Given the rather bizarre requirements (a process that goes forever without using much CPU), this is reasonably compact:
import threading
dummy_event = threading.Event()
dummy_event.wait()
...however, I fear I am succumbing to the temptation to solve your Y and not your X.
Besides which, this won't work if your platform doesn't provide the threading
module. If you try to substitute the dummy_threading
module, dummy_event.wait()
returns immediately.
Update: if you are just keeping a parent process going for the sake of its subprocesses, you can use the wait()
method on Popen objects, or the join()
method on Process
objects. Both of these methods will block indefinitely until the subprocess ends. If you're using some other subprocess API, there's bound to be equivalent functionality available. If not, get the PID of the process and use os.waitpid()
.
Upvotes: 14
Reputation:
What's the issue with sleeping for a very brief period of time? 1 millisecond is close to an eternity to a modern computer. Provided you don't have thousands of these threads (which it sounds like you don't), then there is NOTHING wrong with sleeping for one, ten, ten thousand, or ten million milliseconds every iteration through the loop. The CPU won't even notice this little blip.
Upvotes: 0
Reputation: 2962
If you are relying on this script to perform periodic maintenance, use cron (UNIX) or scheduled tasks (Windows).
If you wish to wait for subprocesses to complete, use os.waitpid
.
If you wish to wait for filesystem activity, use pyinotify.
Upvotes: 3
Reputation: 49850
Don't use busy waiting. Depending on what you are waiting for, use one of the operating system's blocking wait functions, e.g. select
on Unix and WaitForSingleObject
/WaitForMultipleObjects
on Windows.
Upvotes: 3