How to Run Two Async Functions Forever in Python


Async functions, also known as coroutines, are functions that can be paused and resumed during their execution. In Python, the asyncio module, provides a powerful framework for writing concurrent code using coroutines, which are special functions that can be paused and resumed. In this article, we will explore how to run two async functions forever using asyncio in Python.

Async Functions

Async functions, also known as coroutines, are functions that can be paused and resumed during their execution. They allow for concurrent execution of code without blocking the main thread, thus enabling efficient utilization of system resources.

To define an async function in Python, we use the async keyword before the def statement. Within the async function, we can use the await keyword to pause the execution and wait for another async function or coroutine to complete.

Method 1- Using the asyncio module

The asyncio module in Python provides a framework for writing single−threaded concurrent code using coroutines, multiplexing I/O access over sockets and other resources, running network clients and servers, and other related operations. It allows us to write asynchronous code in a structured and organized manner.

Syntax

Here, the asyncio.get_event_loop() function is used to retrieve the current event loop or create a new one if none exists.

Example

In the example below for function1, we have an infinite loop that prints "Function 1" and then pauses for 1 second using await asyncio.sleep(1). Similarly, function2 has an infinite loop that prints "Function 2" and pauses for 2 seconds. By calling asyncio.gather(function1(), function2()) in the main function, we instruct the event loop to execute both functions concurrently. The asyncio.gather function takes care of scheduling and running both functions in an interleaved manner. When we run the Python script, the event loop runs indefinitely, executing both function1 and function2 repeatedly. The output demonstrates this behavior, with the messages from both functions being printed in an interleaved fashion based on their respective time intervals.

import asyncio

async def function1():
    while True:
        print("Function 1")
        await asyncio.sleep(1)  # Pause execution for 1 second

async def function2():
    while True:
        print("Function 2")
        await asyncio.sleep(2)  # Pause execution for 2 seconds

async def main():
    await asyncio.gather(function1(), function2())

if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    try:
        loop.run_until_complete(main())
    finally:
        loop.close()

Output

Function 1
Function 2
Function 1
Function 2
Function 1
Function 1
Function 2
Function 1
Function 1
.
.
.

Method 1- Using Threads

Threads are lightweight and allow concurrent execution of multiple tasks within a single process. In this method, we will utilize the threading module to run two async functions forever.

Syntax

thread1 = threading.Thread(target=async_function1)

Example

In the below example, we have two async functions: async_function1 and async_function2.

  • async_function1 prints "Async function 1" every second using time.sleep(1).

  • async_function2 prints "Async function 2" every two seconds using time.sleep(2).

We create two threads, thread1 and thread2, targeting async_function1 and async_function2 respectively. The Thread class from the threading module is used for creating and managing threads. We then start both threads using the start() method. This initiates the execution of the async functions in separate threads, allowing them to run concurrently.

import threading
import time

def async_function1():
    while True:
        print("Async function 1")
        time.sleep(1)

def async_function2():
    while True:
        print("Async function 2")
        time.sleep(2)

thread1 = threading.Thread(target=async_function1)
thread2 = threading.Thread(target=async_function2)

thread1.start()
thread2.start()

while True:
    pass

Output

The output of this example will continuously print "Async function 1" every second and "Async function 2" every two seconds. The code starts two threads, each executing its respective async function. The main thread is kept alive by an infinite loop to allow the other threads to run indefinitely.

Async function 1
Async function 1
Async function 2
Async function 1
Async function 1
Async function 2
Async function 1
Async function 1
Async function 2

Method 3 - Using subprocesses

Subprocesses are separate processes that can be created and managed from within a Python program. In this method, we will employ the subprocess module to run two async functions forever.

Syntax

subprocess.Popen(args, bufsize=-1, executable=None)

Here,

  • args (required): This parameter specifies the command to be executed. It can be a string or a sequence of strings.

  • bufsize: This parameter represents the buffer size used for I/O operations. The default value is −1, which means the system default buffer size is used.

  • bufsize: This parameter represents the buffer size used for I/O operations. The default value is −1, which means the system default buffer size is used.

Example

In this example, we have the same two async functions: async_function1 and async_function2.

  • async_function1 prints "Async function 1" every second using time.sleep(1).

  • async_function2 prints "Async function 2" every two seconds using time.sleep(2).

Instead of threads, we create subprocesses using the subprocess.Popen class from the subprocess module. Each subprocess is created by executing a separate Python process that runs the respective async function. The subprocesses are created with the subprocess.Popen constructor, and we pass the Python command to execute the desired function. For example, ['python', '-c', 'from module import async_function1; async_function1()'] runs async_function1 from a separate Python process.

import subprocess
import time

def async_function1():
    while True:
        print("Async function 1")
        time.sleep(1)

def async_function2():
    while True:
        print("Async function 2")
        time.sleep(2)

subprocess1 = subprocess.Popen(['python', '-c', 'from module import async_function1; async_function1()'])
subprocess2 = subprocess.Popen(['python', '-c', 'from module import async_function2; async_function2()'])

while True:
    pass

Output

The output of this example will continuously print "Async function 1" every second and "Async function 2" every two seconds. The code creates two subprocesses, each executing its respective async function. The main process is kept alive by an infinite loop to allow the subprocesses to run indefinitely.

Async function 1
Async function 1
Async function 2
Async function 1
Async function 1
Async function 2
Async function 1
Async function 1
Async function 2

Conclusion

In this article, we discussed how we can run two Async functions forever in Python by using the asyncio module in Python. Asynchronous programming with asyncio opens up new possibilities for writing high−performance and responsive Python applications. By leveraging async functions and the event loop, you can utilize the power of concurrency and efficiently manage multiple tasks.

Updated on: 18-Jul-2023

6K+ Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements