Overview
In modern Python development, especially with the advent of Python 3.7 and 3.11, asynchronous programming has become more important than ever. With asyncio
, Python provides a robust set of tools for writing concurrent code using coroutines. In this tutorial, we’ll explore how to use asyncio
in Python 3.11 (or higher) to display a loading indicator in the terminal while waiting for a task to complete. This can enhance the user experience in CLI applications by providing visual feedback during long-running operations.
Understanding asyncio
Before we dive into the implementation of the loading indicator, let’s briefly touch on what asyncio
is. asyncio
is a library in Python that provides infrastructure for writing single-threaded concurrent code using coroutines, multiplexing I/O access over sockets and other resources, running network servers, and other related primitives. In simple terms, it lets you write code that can handle a lot of I/O-bound and high-level structured network code asynchronously.
Setting up Your Environment
Ensure you’re running Python 3.11 or newer. You can check your Python version by running python --version
in your terminal. If you’re not on Python 3.11, consider using a tool like pyenv to manage multiple Python versions.
Writing an Asynchronous Loading Indicator
Let’s dive into writing the asynchronous loading indicator. The idea is to display a simple animation (like a rotating `|/-\` symbol) in the terminal while an asynchronous task is running and to stop it once the task is complete.
import asyncio
import itertools
import sys
def print_with_carriage_return(status):
sys.stdout.write('\r' + status)
sys.stdout.flush()
class LoadingIndicator:
def __init__(self, msg='Loading...', symbols='|/-\\'):
self.msg = msg
self.symbols = itertools.cycle(symbols)
async def start(self):
while True:
sys.stdout.write('\r' + self.msg + ' ' + next(self.symbols))
sys.stdout.flush()
await asyncio.sleep(0.1)
async def stop(self):
sys.stdout.write('\r')
sys.stdout.flush()
We have created a class LoadingIndicator
that when its start
method is called, will print the loading message along with the symbols in rotation. To stop the indicator, the stop
method clears the line.
Integrating the Loading Indicator with Asyncio
To use the loading indicator, you will need to run it concurrently with your main async task, allowing it to update the terminal output while the main task is still in progress. Here’s how you can integrate both:
import asyncio
async def main_task(duration=10):
# simulate a long-running task
await asyncio.sleep(duration)
print("\nTask completed!")
async def main():
loader = LoadingIndicator()
loader_task = asyncio.create_task(loader.start()) # Start loading indicator
await main_task() # This simulates your long-running task
await loader.stop() # Stop the loading indicator after the task is completed
if __name__ == '__main__':
asyncio.run(main())
In this example, the main_task
simulates a long-running operation with asyncio.sleep
. We then create a task for the LoadingIndicator
‘s start
method using asyncio.create_task()
, which starts the loading animation. After main_task
completes, loader.stop()
is called to stop the animation.
Handling Multiple Asynchronous Tasks
In more complex applications, you might find yourself managing multiple asynchronous tasks alongside the loading indicator. The following example shows how to use asyncio.gather
to run multiple tasks concurrently:
import asyncio
async def additional_task(time):
await asyncio.sleep(time)
async def main():
loader = LoadingIndicator()
tasks = [loader.start(), main_task(), additional_task(5)]
await asyncio.gather(*tasks)
await loader.stop() # Be sure to stop the loader
if __name__ == '__main__':
asyncio.run(main())
Note that in this setup, you will need to manually ensure that loader.stop()
is called after all tasks have been completed to properly stop the loading indicator.
Conclusion
You’ve learned how to created a loading indicator from scratch in Python. You can modify the code or extend it to make the result even better. Try to remove some lines of code, add your own code, and see what happens next. The tutorial ends here. Happy coding & have a nice day!