Async programming Python

How to Get Started with Asynchronous Programming in Python

Async IO is a popular programming design that is supported on Python. Asynchronous development takes a program through a set of unique operations in a sequential manner. Execution flows in such development designs follow a simple step, and proceed to the next one only once the previous object is cleared.

Asynchronous programming can improve lag time, and also result in better task speed. The solutions achieved through asynchronous programming can open doors to innovation in programming, and also lead towards better management and solutions. Developers get to initiate new techniques, and also work on overall improvement in the process.

 In this article, we take a look at asynchronous programming in Python, and help you get started with the right set of codes and solutions. Stay with us for more.

Asynchronous Programming on Python

Python follows a centralized FIFO or first in first out method of data structure. The queuing structure can be complex, but heavily organized and well-managed. The program can be initiated with the code below:

import queue
 2
 3  def task(name, work_queue):
 4    if work_queue.empty():
 5        print(f"Task {name} nothing to do")
 6    else:
 7        while not work_queue.empty():
 8            count = work_queue.get()
 9            total = 0
10            print(f"Task {name} running")
11            for x in range(count):
12                total += 1
13            print(f"Task {name} total: {total}")
14
15  def main():
16    """
17    This is the main entry point for the program
18    """
19    # Create the queue of work
20    work_queue = queue.Queue()
21
22    # Put some work in the queue
23    for work in [15, 10, 5, 2]:
24        work_queue.put(work)
25
26    # Create some synchronous tasks
27    tasks = [(task, "One", work_queue), (task, "Two", work_queue)]
28
29    # Run the tasks
30    for t, n, q in tasks:
31        t(n, q)
32
33  if __name__ == "__main__":
34    main()

Each of the actions play a specific part. Line 20 is the important one to note here, as this is where the queue is actually connected and created.

Concurrency Example 

Concurrency is a type of asynchronous coding on Python, which is focused on running multiple loops at one time. An example of concurrency is mentioned below:

import queue
 2
 3  def task(name, queue):
 4    while not queue.empty():
 5        count = queue.get()
 6        total = 0
 7        print(f"Task {name} running")
 8        for x in range(count):
 9            total += 1
10            yield
11        print(f"Task {name} total: {total}")
12
13   def main():
14    """
15    This is the main entry point for the program
16    """
17    # Create the queue of work
18    work_queue = queue.Queue()
19
20    # Put some work in the queue
21    for work in [15, 10, 5, 2]:
22        work_queue.put(work)
23
24    # Create some tasks
25    tasks = [task("One", work_queue), task("Two", work_queue)]
26
27    # Run the tasks
28    done = False
29    while not done:
30        for t in tasks:
31            try:
32                next(t)
33            except StopIteration:
34                tasks.remove(t)
35            if len(tasks) == 0:
36                done = True
37
38   if __name__ == "__main__":
39    main()

Each line plays an integral role here. Line 36 marks completion of the code, and sets it aside as complete.

Concurrency with Blocking Calls

Besides the simple concurrency, there is another form as well that works with blocking calls:

import time
 2  import queue
 3  from codetiming import Timer
 4
 5  def task(name, queue):
 6    timer = Timer(text=f"Task {name} elapsed time: {{:.1f}}")
 7    while not queue.empty():
 8        delay = queue.get()
 9        print(f"Task {name} running")
10        timer.start()
11        time.sleep(delay)
12        timer.stop()
13        yield
14
15  def main():
16    """
17    This is the main entry point for the program
18    """
19    # Create the queue of work
20    work_queue = queue.Queue()
21
22    # Put some work in the queue
23    for work in [15, 10, 5, 2]:
24        work_queue.put(work)
25
26    tasks = [task("One", work_queue), task("Two", work_queue)]
27
28    # Run the tasks
29    done = False
30    with Timer(text="\nTotal elapsed time: {:.1f}"):
31        while not done:
32            for t in tasks:
33                try:
34                    next(t)
35                except StopIteration:
36                    tasks.remove(t)
37                if len(tasks) == 0:
38                    done = True
39
40  if __name__ == "__main__":
41    main()

Concurrency with Non-Blocking calls

Asynchronous programming on Python can be used for concurrency with non-blocking calls as well:

import asyncio
 2 from codetiming import Timer
 3
 4 async def task(name, work_queue):
 5    timer = Timer(text=f"Task {name} elapsed time: {{:.1f}}")
 6    while not work_queue.empty():
 7        delay = await work_queue.get()
 8        print(f"Task {name} running")
 9        timer.start()
10        await asyncio.sleep(delay)
11        timer.stop()
12
13  async def main():
14    """
15    This is the main entry point for the program
16    """
17    # Create the queue of work
18    work_queue = asyncio.Queue()
19
20    # Put some work in the queue
21    for work in [15, 10, 5, 2]:
22        await work_queue.put(work)
23
24    # Run the tasks
25    with Timer(text="\nTotal elapsed time: {:.1f}"):
26        await asyncio.gather(
27            asyncio.create_task(task("One", work_queue)),
28            asyncio.create_task(task("Two", work_queue)),
29        )
30
31   if __name__ == "__main__":
32    asyncio.run(main())

Asynchronous HTTP Calls (Blocking)

There is a different process for HTTP calls that are blocked:

import queue
 2  import requests
 3  from codetiming import Timer
 4
 5   def task(name, work_queue):
 6    timer = Timer(text=f"Task {name} elapsed time: {{:.1f}}")
 7    with requests.Session() as session:
 8        while not work_queue.empty():
 9            url = work_queue.get()
10            print(f"Task {name} getting URL: {url}")
11            timer.start()
12            session.get(url)
13            timer.stop()
14            yield
15
16   def main():
17    """
18    This is the main entry point for the program
19    """
20    # Create the queue of work
21    work_queue = queue.Queue()
22
23    # Put some work in the queue
24    for url in [
25        "http://google.com",
26        "http://yahoo.com",
27        "http://linkedin.com",
28        "http://apple.com",
29        "http://microsoft.com",
30        "http://facebook.com",
31        "http://twitter.com",
32    ]:
33        work_queue.put(url)
34
35    tasks = [task("One", work_queue), task("Two", work_queue)]
36
37    # Run the tasks
38    done = False
39    with Timer(text="\nTotal elapsed time: {:.1f}"):
40        while not done:
41            for t in tasks:
42                try:
43                    next(t)
44                except StopIteration:
45                    tasks.remove(t)
46                if len(tasks) == 0:
47                    done = True
48
49   if __name__ == "__main__":
50    main()

Non-blocking HTTP Calls

Non-blocking HTTP calls follow the code below:

import asyncio
 2  import aiohttp
 3  from codetiming import Timer
 4
 5  async def task(name, work_queue):
 6    timer = Timer(text=f"Task {name} elapsed time: {{:.1f}}")
 7    async with aiohttp.ClientSession() as session:
 8        while not work_queue.empty():
 9            url = await work_queue.get()
10            print(f"Task {name} getting URL: {url}")
11            timer.start()
12            async with session.get(url) as response:
13                await response.text()
14            timer.stop()
15
16   async def main():
17    """
18    This is the main entry point for the program
19    """
20    # Create the queue of work
21    work_queue = asyncio.Queue()
22
23    # Put some work in the queue
24    for url in [
25        "http://google.com",
26        "http://yahoo.com",
27        "http://linkedin.com",
28        "http://apple.com",
29        "http://microsoft.com",
30        "http://facebook.com",
31        "http://twitter.com",
32    ]:
33        await work_queue.put(url)
34
35    # Run the tasks
36    with Timer(text="\nTotal elapsed time: {:.1f}"):
37        await asyncio.gather(
38            asyncio.create_task(task("One", work_queue)),
39            asyncio.create_task(task("Two", work_queue)),
40        )
41
42   if __name__ == "__main__":
43    asyncio.run(main())

By following our basic guide, you are now caught up with how async programming on Python functions. This article helps give the coding tools and knowledge needed for developers to follow asynchronous programming techniques and implement solutions.