Can Conditional Function loops use Python asyncio to reduce CPU load?

I think the code I’m using in my conditional functions is causing high CPU loads due to the short Period time I need to set in order for the Function to behave like I need it to… basically I need it to check a measurement every 3 seconds, so the loop is pretty much constantly running, and while that is happening, nothing else is getting the CPU time it needs, and the whole system becomes unstable.
Whenever I have these Conditional Functions activated I end up having problems with Mycodo dropping measurements and the database locking… which inevitably leads to a total system crash.
This undesirable behavior tends to happen more often on slower model Pis like the Pi 3B+ and less on faster models like the Pi 4… which leads me to believe that the Conditional code I’m currently using is really hammering the CPU.
While I believe part of the issue is Python itself, or more to the point Python’s interpreter using more resources compared to a language like C++… I have been reading about using asynchronous coding to possibly reduce CPU loads that can be caused by loops.

Here is an example of one of my Conditional Functions that is causing high CPU loads due to the need to have it constantly checking for the condition every 3 seconds…

from time import sleep
from datetime import datetime
self.loop_count = 0
blinks=8
measurement = self.condition("1c8c49f3") #VPD [Function24] Status LED Conditional
if measurement is not None:  # If a measurement exists
    if measurement < 0.8:  # led is dark blue
        self.run_action("1a811689", value={"payload": "0,0,2"})
    elif measurement >= 0.8 and measurement < 1.3:  # led is green
        self.run_action("1a811689", value={"payload": "0,1,0"})
    elif measurement >= 1.3 and measurement < 1.45:  # led is yellow
        self.run_action("1a811689", value={"payload": "1,1,0"})
    elif measurement >= 1.45:  # led is bright red
        self.run_action("1a811689", value={"payload": "2,0,0"})
else:  # If no measurement exists led is flashing bright blue
    for _ in range(blinks):
        self.run_action("1a811689", value={"payload": "0,0,10"})
        sleep(.75)
        self.run_action("1a811689", value={"payload": "0,0,0"})
        sleep(.75)

I would like to figure out if it would be possible to use asynchronous code (using asyncio and await) to create “pauses” where appropriate in the loop so that other processes can get their fair share of CPU time and prevent the Conditional from hogging the CPU.

Unfortunately I am not really a programmer… I don’t know if I should be placing the “asyncio” and “await” commands in the for loop, or the if-elif loop, or both? Or if I simply need to add some “sleep” timers or “end” or “exit” the loop after each iteration to allow other tasks to have more CPU time?

If anyone with more coding experience has any suggestions or can point me to any relevant code examples on how I can better streamline this code to make it less CPU intensive I’m all ears. I would really like to get these conditionals fixed and working without causing crashes… if I can make that happen I’d like to post a How-To on building a really useful WiFi NeoPixel LED status board that runs on an ESP32 with Tasmota and mimics the Output indicators and gauges in the Mycodo Dashboard… without having to open a browser and load a Dashboard :wink:
Thank you in advance.

Enclose your code in backticks to preserve indentations, so it can be read. Also, I would remove the line numbers, since if anyone wants to copy your code, they will then have to manually remove every line number before it can be executed. Line numbers also interfere with the forum’s ability to properly syntax hilight.

1 Like

There’s some fundamental misunderstandings here. Let me see if I can help with some.

First asyncio is for application control flow. This means that asyncio allows your application, I.e. your Python code, to not wait on certain tasks. Lets say you were reading sensor data for 3 seconds but also wanted to control the blinking light at the same time. You’d use asyncio to call a function that reads the sensor then control the light then get the result. Keep in mind this is entirely within your program.

Now there’s the operating system the Python thread and everything else. Your OS is constantly pausing threads to pick up others and doing all kinds of sudo parallel work. The sleep function (read the docs) already relinquishes the thread to the operating system. Roughly meaning the OS will either pick up other work for at least N seconds or will free up some compute power.

All this to say, there is an extremely small chance the problems you’re having is related to using the sleep function. You can confirm by inspecting CPU usage if you’d like. Hopefully this helps you avoid a rabbit hole on asyncio and frees you up to find your real problem.

1 Like

I meant to follow up about this, once the code was more readable…

If you’re certain this is the function that’s causing high CPU loads, I would first do some tests to determine if it’s the self.condition("1c8c49f3") or self.run_action("1a811689") that’s causing the load. I would remove each, so only either condition() or run_action() is executing, and see if the load changes. From there, I’d look into the code for that condition() or run_action() for potential issues. What is the exact Condition being used? Is the Action the Neopixel: Change Pixel Color?

After moving the OS and Mycodo to an external SSD drive connected to one of the Pi4’s USB 3 ports, the undesirable behavior I was experiencing before seems to have stopped altogether. I believe that there is still some issue in the code for the conditional that is causing high CPU loads, but the real problem seems to have been an IO throughput issue… the SD card write speed simply could not keep up with everything the OS and Mycodo was doing. Since moving to an SSD drive I have not had any problems with Mycodo dropping measurements, or any issues with the database locking or the system crashing. For now I am writing this off as a hardware limitation of the Pi and the SD card.