Zeke Marffy
Zeke Marffy

Reputation: 328

How does one stop the main thread when a Python concurrent future object finishes, without polling?

I have a function that shows a progress bar while another function runs, using concurrent.futures.ThreadPoolExecutor.

def run_with_loading(function, args=[], kwargs={}, phrase="Loading...", bar_length=5):
    '''
    Run a function while showing a loading bar.
    '''
    with concurrent.futures.ThreadPoolExecutor(max_workers=1) as executor:
        f = executor.submit(function, *args, **kwargs)
        while True:
            for i in range(bar_length):
                if f.done():
                    result = f.result()
                    if f.exception() or not result[0]:
                        c = "✗"
                    else:
                        c = "✔"
                    print(f"\33[2K\r{phrase} {c}")
                    return result
                sys.stdout.write(
                    f"\r{phrase} {'□' * i}{'■'}{'□' * (bar_length - i - 1)}")
                sys.stdout.flush()
                time.sleep(0.2)

Yet this still polls to see if the function spawned is done, every 0.2 seconds. While this works, I am wondering if there is any more efficient way to notify the run_with_loading function that the function it started has finished. I need to retain whether there is an exception or not, which is made clear in the code, so it can print .

Upvotes: 0

Views: 549

Answers (1)

KimKulling
KimKulling

Reputation: 2833

Instead of polling for the result you should use concurrent.futures.as_completed to loop through the results:

with concurrent.futures.ThreadPoolExecutor(max_workers=1) as executor:
    futures = []
    futures.append(executor.submit(function, *args, **kwargs))
    for future in concurrent.futures.as_completed(futures):
        result = f.result()
        if f.exception() or not result[0]:
            c = "✗"
        else:
            c = "✔"
        print(f"\33[2K\r{phrase} {c}")

You can find the documentation here: Futures doc The function as_completed an iterator to go through all finished futures, which has ended successfully.

You need to adapt your bar_length approach, but hopefully, this helps you to get another idea of how to wait for your results.

Upvotes: 1

Related Questions