Python: "while" is too slow, and sleep(0.25) becomes sleep(3) in actual execution
<p>I am running a Python Program on a Raspberry Pi 3 which I want to log the temperature from a DS18B20 sensor once every 0.25 seconds.</p>

<p>Earlier, when the program was simple and displaying the temperature on shell, it was quite fast and not having issues. Unfortunately due to the program itself now which includes logging to a file, I am getting a log every 2 seconds or 3 seconds only.</p>

<p>How do I ensure the 0.25 second logging interval.</p>

<p>I have shared the code below:</p>

<pre><code>#This program logs temperature from DS18B20 and records it
#Plots the temperature-time plot.

import os
import sys
#import matplotlib.pyplot as plt
from re import findall
from time import sleep, strftime, time
from datetime import *

#plt.ion()
#x = []
#y = []

ds18b20 = ''

def setup():
    global ds18b20
    for i in os.listdir('/sys/bus/w1/devices'):
        if i != 'w1_bus_master1':
            ds18b20 = i

# Reads temperature data from the Temp sensor
# This needs to be modified for use with max31855 and K-type thermocouples
def read():
#   global ds18b20
    location = '/sys/bus/w1/devices/' + ds18b20 + '/w1_slave'
    tfile = open(location)
    text = tfile.read()
    tfile.close()
    secondline = text.split("\n")[1]
    temperaturedata = secondline.split(" ")[9]
    temperature = float(temperaturedata[2:])
    temperature = temperature / 1000
    return temperature

#Loop for logging - sleep, and interrupt to be configured.
def loop():
        while True:
                if read() != None:
                        print "Current temperature : %0.3f C" % read()
                        #sleep(0.25)
                        func()

def write_temp(temperature,file_name):
        with open(file_name, 'a') as log:
                log.write("{0},{1}\n".format(datetime.now().strftime("%d-%m-%Y %H:%M:%S"),str(temperature)))

arg = sys.argv[1]
filename1 = str(arg) + "-" + datetime.now().strftime("%d-%m-%Y-%H-%M-%S")+".csv"

def func():
        temperature = read()
        #sleep(0.25)
        write_temp(temperature,filename1)
        #graph(temperature)

#For plotting graph using MatPlotLib
#Comment out this function during foundry trials to avoid system slowdown
#Check system resource usage and slowdown using TOP or HTOP

#def graph(temperature):
#        y.append(temperature)
#        x.append(time())
#        plt.clf()
#        plt.scatter(x,y)
#        plt.plot(x,y)
#        plt.draw()              

#Interrupt from command-line
def destroy():
    pass

if __name__ == '__main__':
    try:
        setup()
        func()
        loop()
    except KeyboardInterrupt:
        destroy()
</code></pre>

<p>I have commented out sections that I thought to be resource heavy, but still I can't manage anything less than 2 seconds. I am getting results as below:</p>

<p><strong>Output:</strong></p>

<pre><code>27-09-2016 12:18:41,23.0
27-09-2016 12:18:43,23.062
27-09-2016 12:18:46,23.125
27-09-2016 12:18:48,23.187
27-09-2016 12:18:50,23.187
27-09-2016 12:18:53,23.562
27-09-2016 12:18:55,25.875
27-09-2016 12:18:58,27.187
27-09-2016 12:19:00,27.5
</code></pre>

<ol>
<li>Only open the logfile once (and close it on program exit)</li>
<li>Don't always re-read the temperature from the sensor. You call <code>read()</code> way too often.</li>
<li>Reduce general overhead and simplify your calls.</li>
</ol>

<p>I am not able to completely test this, but something like this sould work:</p>

<pre><code>import os
import sys
import time
from datetime import datetime

def read_temp(dev):
    '''Reads temperature from sensor and returns it as float.'''
    loc = '/sys/bus/w1/devices/' + dev + '/w1_slave'
    with open(loc) as tf:
        return float(tf.read().split('\n')[1].split(' ')[9][2:]) / 1000.0

def write_temp(t, logfile):
    '''Writes temperature as .3 float to open file handle.'''
    logfile.write('{0},{1:.3f}\n'.format(datetime.now().strftime('%d-%m-%Y %H:%M:%S'), t))

def loop(dev, logfile):
    '''Starts temperature logging until user interrupts.'''
    while True:
        t = read_temp(dev)
        if t:
            write_temp(t, logfile)
            print('Current temperature: {0:.3f} Â°C'.format(t))
            sys.stdout.flush() # Flush. Btw, print is time-consuming!
            time.sleep(.25)

if __name__ == '__main__':
    # Take the first match for a device that is not 'w1_bus_master1'
    dev = [d for d in os.listdir('/sys/bus/w1/devices') if d != 'w1_bus_master1'][0]
    # Prepare the log filename
    fname = str(sys.argv[1]) + "-" + datetime.now().strftime("%d-%m-%Y-%H-%M-%S")+".csv"
    # Immediately open the log in append mode and do not close it!
    logfile = open(fname, 'a')

    try:
        # Only pass device and file handle, not the file name.
        loop(dev, logfile)
    except KeyboardInterrupt:
        # Close log file on exit
        logfile.close()
</code></pre>

python runtime raspberry-pi3