Share
Explore

PYTHON Asynchronous libraries and threading in Python


Learning Outcomes:

How to use async features and threading for handling tasks with high latency (long running / time delay) for long-running processes.

Here's an example of a Python laboratory activity designed to help understand asynchronous programming and threading in Python.
This lab activity will walk through examples using Python's asyncio library and the threading module, showing how each can be used to handle tasks with high latency or long-running processes.

Let’s do this in Google Collab: works with Gmail Login Credentials
image.png
Share LINK to Instructor’s Google Collab Notebook:

Laboratory Exercise: Asynchronous Programming and Threading in Python

Objectives:

Understand and apply the asyncio library for asynchronous programming.
Learn to use the threading module for managing multiple threads.
Compare asynchronous programming with multi-threading in handling I/O-bound and CPU-bound tasks.

Requirements:

Python 3.7 or higher
Access to a Python interactive environment such as Jupyter Notebook or any IDE that supports Python.
Basic understanding of Python syntax and functions.

Part 1: Exploring Asynchronous Programming with asyncio

Step 1: Introduction to asyncio


import asyncio

# Define an asynchronous function using 'async def'
async def greet(delay, name):
await asyncio.sleep(delay) # Simulates a delay, non-blocking
print(f"Hello, {name}!")

# This is the main entry point for the asyncio program
async def main():
# Schedule asynchronous executions with different delays
await asyncio.gather(
greet(1, 'Alice'),
greet(2, 'Bob'),
greet(3, 'Charlie')
)

# Run the event loop
asyncio.run(main())

image.png

Comments:
asyncio.sleep() simulates I/O by sleeping asynchronously without blocking the event loop.
asyncio.gather() runs multiple coroutines concurrently.

Step 2: Asynchronous HTTP Requests

Install the required library:
pip install aiohttp

import aiohttp
import asyncio

async def fetch_url(url):
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
print(f"Response from {url}: {response.status}")
return await response.text()

async def main():
urls = ["http://example.com", "https://api.github.com"]
responses = await asyncio.gather(*(fetch_url(url) for url in urls))
print(responses[0][:100]) # Print first 100 characters of the response

asyncio.run(main())

Comments:
aiohttp.ClientSession() provides a session for making HTTP requests.
asyncio.gather() is used again to handle multiple requests simultaneously.

Here's an adaptation of the program from the asynchronous programming section that fetches URLs and writes the contents retrieved from each website to its own file in the current default directory.

This version uses the aiohttp library for making HTTP requests asynchronously and incorporates file writing operations:


import asyncio
import aiohttp

async def fetch_and_save(url):
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
content = await response.text()
# Create a filename from the URL
file_name = url.replace('https://', '').replace('http://', '').replace('/', '_') + '.txt'
# Write the content to a file in the default directory
with open(file_name, 'w', encoding='utf-8') as f:
f.write(content)
print(f"Content from {url} has been written to {file_name}")

async def main():
urls = ["http://example.com", "https://api.github.com"]
# Start tasks to fetch URLs and write contents to files
await asyncio.gather(*(fetch_and_save(url) for url in urls))

# Run the main function to start the async program
asyncio.run(main())


Explanation of Changes:
Function fetch_and_save: This function handles both fetching the website content and writing it to a file.
It generates a filename by stripping the protocol from the URL (http or https) and replacing slashes with underscores to avoid directory traversal issues.
It then writes the content it retrieves to this file.

File Writing: The open() function is used to create and write to the file in 'write' mode ('w'). This ensures that any existing file with the same name is overwritten. The filename is created dynamically from the URL to ensure uniqueness for each site's content.

Error Handling: Basic error handling such as checking the response status or handling exceptions during the HTTP request or file operations is assumed to be part of the production-level code and should be added based on specific requirements.

This script demonstrates how to combine asynchronous HTTP requests with file I/O in Python, useful for web scraping tasks, data collection, or caching web content locally.



Part 2: Using Threading for Long-Running Tasks

Step 1: Basic Threading Example

import threading
import time

def print_numbers():
for i in range(1, 6):
time.sleep(1)
print(i)

# Create a thread that runs the print_numbers function
thread = threading.Thread(target=print_numbers)
thread.start()

# Continue with the main thread
print("Thread started")
thread.join() # Wait for the thread to complete
print("Thread has completed")

Comments:
threading.Thread() is used to create a new thread.
.join() makes the main thread wait until the created thread completes.

Step 2: Threading with I/O Operations

import threading

def save_to_file(file_path, data):
with open(file_path, 'w') as file:
file.write(data)

# Thread target function for reading from a file
def read_from_file(file_path):
with open(file_path, 'r') as file:
print(file.read())

# Writing data to file in a thread
thread_write = threading.Thread(target=save_to_file, args=('test.txt', 'Hello, World!'))
thread_write.start()
thread_write.join()

# Reading data from file in another thread
thread_read = threading.Thread(target=read_from_file, args=('test.txt',))
thread_read.start()
thread_read.join()

Comments:
Utilizing threads to perform I/O operations allows the main program to continue running without waiting for the I/O operations to complete, unless explicitly joined.

Conclusion:

This lab provides a practical understanding of how asynchronous programming with asyncio and threading can be used to efficiently handle tasks that involve high latency operations or long-running processes.
Experiment by modifying the tasks or combining threading with asyncio to observe different behaviors and performances.
Want to print your doc?
This is not the way.
Try clicking the ⋯ next to your doc name or using a keyboard shortcut (
CtrlP
) instead.