简体   繁体   中英

CPU usage/ speed tradeoff when reading from a named pipe in python

I want to read from a pipe asynchronously in python. The pipe is fed continuously from another process (a javascript process). I am using pipes for a matter of speed.

I don't want to loop and see if new lines are appended to the file, because it takes 100% of the CPU. I have tried watchgod awatch , but it adds a 300ms delay. My tradeoff is an asyncio.sleep of 1ms, it takes 10% of the CPU but adds 1ms delay.

import json
import time

import aiofiles
# from watchgod import awatch


async def amain():
    async with aiofiles.open('pipe_a', mode='r') as f:
        # async for changes in awatch('pipe_a'): # CPU=0% TIME=300ms
        while True:
            async for line in f:
                x = json.loads(line)
                print(f"pong: {time.time() * 1000 - x['time']} ms")
            await asyncio.sleep(0.001) # # CPU=10% TIME=1.5ms
            # await asyncio.sleep(0) # # CPU=100% TIME=0.5ms


import asyncio

loop = asyncio.get_event_loop()

loop.run_until_complete(amain())

What is the right way to get 0.5ms delay, and 0% CPU usage?

Watchgod awatch is doing an async loop itself. So that's why it took 300ms as the delay of the default loop is 300ms.

On Linux, to watch file change, one must use inotify . There is an async library for inotify on python: aionotify . Waiting for file changes using notify does not block the CPU and catches the file event as soon as it appears.

The solution takes 0% CPU usage and a 0.5ms delay:

import asyncio
import aiofiles
import aionotify
import json
import time

watcher = aionotify.Watcher()
watcher.watch(alias='logs', path='pipe_a', flags=aionotify.Flags.MODIFY)

# Prepare the loop
loop = asyncio.get_event_loop()


async def amain():
    await watcher.setup(loop)
    async with aiofiles.open('pipe_a', mode='r') as f:
        try:
            while True:
                _ = await watcher.get_event()
                async for line in f:
                    x = json.loads(line)
                    print(f"pong: {time.time() * 1000 - x['time']} ms")
        finally:
            watcher.close()


loop.run_until_complete(amain())
loop.stop()
loop.close()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM