34

I am attempting to communicate with a device over serial using Pyserial. As commands need to be continually sent, they have to be placed in a while loop in Python.

I am currently using this code, and have taken a look at python process takes 100% CPU:

while True:
    #do some serial sending here
    time.sleep(0.2)

This code works. However, the sending speed is slow. I tried to make it faster by decreasing the sleep interval, but it seems to load the CPU a bit too much.

In short, is there a any way to effectively iterate over a while loop forever, while still maintaining a low consumption of CPU resources?

Community
  • 1
  • 1
jhtong
  • 1,529
  • 4
  • 23
  • 34
  • based on this [post](http://stackoverflow.com/questions/529034/python-pass-or-sleep-for-long-running-processes), time.sleep has very little overhead, you might want to check your serial sending part of code – xvatar Jun 07 '12 at 06:00
  • 1
    Have you tried sleeping for 0.00001? It may seem ridiculous, but that delay can make all the diference in the world for your CPU. Please try it. – jakebird451 Jun 07 '12 at 06:15
  • How can a modern computer break into sweat writing to a serial port? Wouldn't serial.Serial().write() block while writing? That seems ample time for the CPU to do other things? – Bittrance Jun 07 '12 at 06:26
  • apparently, it is a looping problem. @jakebird451 I will try that. However, at 9600 baud the serial's buffer might be flooded. Guess I would have to implement some switching code in the microprocessor. :( Thank you.. – jhtong Jun 07 '12 at 08:07
  • @jakebird451: Doesn't seem to work, the CPU is at an even higher consumption rate. Guess I will stick to 0.2 secs, and implement a switching process to reduce the number of commands sent. Thanks though. – jhtong Jun 07 '12 at 08:11
  • It's not a looping problem, you're simply misunderstanding computing concepts. Think about it. You're expecting the program to "do more" without it taking up more cpu time. It just doesn't work that way. – Zoran Pavlovic Aug 27 '12 at 18:56

3 Answers3

67

The slow CPU wasting part is the "do serial sending". The while loop with just a short sleep will use negligible CPU.

Can you show the serial sending code. There may be a way to speed that up.

On this rather slow CPU I see this:

import time
while True: time.sleep(0.2)      # 0% CPU
while True: time.sleep(0.02)     # 0% CPU
while True: time.sleep(0.002)    # 0.5% CPU
while True: time.sleep(0.0002)   # 6% CPU
while True: time.sleep(0.00002)  # 18% CPU

Now do some extra work in the loop:

import time
while True: range(10000) and None; time.sleep(0.2)      # 1% CPU
while True: range(10000) and None; time.sleep(0.02)     # 15% CPU
while True: range(10000) and None; time.sleep(0.002)    # 60% CPU
while True: range(10000) and None; time.sleep(0.0002)   # 86% CPU

I ran those in the interpreter and stopped each while loop with ctrl-C.

John La Rooy
  • 295,403
  • 53
  • 369
  • 502
  • Alternatively, I could limit the passing to serial using a switch, however, the means reprogramming the embedded device as well. The code looks something like command = 'w' while True: if (command != x): #pyserial send the string here, in this case w. changed through external handler. else: #tell pyserial to close connection – jhtong Jun 07 '12 at 07:30
  • Looks like I have to implement a switching check on both the computer and the microprocessor side, to reduce the number of commands sent. Then stick to sleep(0.2) so that CPU usage is not as high. i.e. save the last command, and if it has been sent, do not send it again. meanwhile, the microprocessor will wait for a halting command 'x'. If not received, it will continue to process the current / previous command at its own pace. – jhtong Jun 07 '12 at 08:14
  • If you're microcontroller will "continue to process current command at its own pace", then a while loop is NOT needed on your python code. I doubt that any sort of library for serial port communication would _require_ you to call any sort of while loop. Perhaps re-read the library documentation as it sounds like you're using it wrong. – Zoran Pavlovic Aug 27 '12 at 18:52
7

In regards to your comment on Joachim's answer:

Then your microcontroller code needs a redesign. Otherwise you're just turning you general-purpose computer into nothing more than a dumb "microcontroller" that iterates over unneeded code repeatedly, hence the 100% cpu. Another symptom of you using your computer incorrectly is the fact that your hardware motor's speed depends on the speed at which you send commands to it via the serial interface. You need to "command" it with the computer which will host your high-level logic. And your micro-controller needs to handle the low-level, repetative control of the motor.

Zoran Pavlovic
  • 1,166
  • 2
  • 23
  • 38
3

You have to figure out the tradeoff you are willing to have between speed and CPU load.

If you have to send short bursts of data, while not doing so much between messages, then maybe you can live with high CPU load for a short time as the average might still be low.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • Thanks, however, that might mean reprogramming the microcontroller to use switches. It has to go forward, hence 'w' has to be sent. If there is no 'w' key detected, the motor will not move. Hence, if it is sent too slowly, the motor will move even slower. – jhtong Jun 07 '12 at 07:36