Reputation: 328
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
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