pistacchio
pistacchio

Reputation: 58953

Best way to implement a non-blocking wait?

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

Answers (6)

Archimedes Trajano
Archimedes Trajano

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

Dimos Koul
Dimos Koul

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

detly
detly

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

user124493
user124493

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

drxzcl
drxzcl

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

Philipp
Philipp

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

Related Questions