This rule raises an issue when synchronous OS calls like os.wait() are used within asynchronous functions.
Using synchronous operating system calls like os.wait(), os.waitpid(), or similar functions in asynchronous code blocks
the entire event loop. This undermines the primary advantage of asynchronous programming - the ability to perform concurrent operations without
blocking execution.
When an async function makes a synchronous OS call:
Instead, async libraries provide mechanisms to run blocking operations in separate threads without blocking the event loop:
asyncio.loop.run_in_executor() for asyncio trio.to_thread.run_sync() for Trio anyio.to_thread.run_sync() for AnyIO Using these constructs allows other tasks to continue executing while waiting for the blocking OS call to complete.
Use asyncio.loop.run_in_executor() to run blocking OS calls in a separate thread pool.
import os
async def wait_for_child_process(pid):
pid, status = os.waitpid(pid, 0) # Noncompliant
return status
import asyncio
import os
async def wait_for_child_process(pid):
loop = asyncio.get_running_loop()
pid, status = await loop.run_in_executor(
None,
os.waitpid, pid, 0
)
return status
Use trio.to_thread.run_sync() to run blocking OS calls in a worker thread.
import os
async def wait_for_child_process(pid):
pid, status = os.waitpid(pid, 0) # Noncompliant
return status
import trio
import os
async def wait_for_child_process(pid):
pid, status = await trio.to_thread.run_sync(
os.waitpid, pid, 0
)
return status
Use anyio.to_thread.run_sync() to run blocking OS calls in a worker thread.
import os
async def wait_for_child_process(pid):
pid, status = os.waitpid(pid, 0) # Noncompliant
return status
import anyio
import os
async def wait_for_child_process(pid):
pid, status = await anyio.to_thread.run_sync(
os.waitpid, pid, 0
)
return status