2012-11-02 8 views
5

Czytam dane szeregowe z pętlą while. Nie mam jednak kontroli nad częstotliwością próbkowania.Jak mogę się upewnić, że pętla while w Pythonie zajmuje określony czas?

Sam kod wydaje się zajmować 0,2 s, więc wiem, że nie będę mógł jechać szybciej. Ale chciałbym móc kontrolować dokładnie, o ile wolniej próbuję.

Czuję, że mógłbym to zrobić za pomocą "uśpienia", ale problemem jest to, że w różnych punktach sama pętla będzie wymagać więcej czasu (w zależności od tego, co dokładnie transmitowane są dane szeregowe), więc kod musiałby uzupełnić saldo.

Na przykład, powiedzmy, że chcę próbkować co 1 s, a pętla trwa od 0,2 s do 0,3 s, aby uruchomić. Mój kod musi być wystarczająco inteligentny, aby spać przez 0,8 s (jeśli pętla trwa 0,2 s) lub 0,7 s (jeśli pętla trwa 0,3 s).

import serial 
import csv 
import time 

#open serial stream 
    while True: 

     #read and print a line 
     sample_value=ser.readline() 
     sample_time=time.time()-zero 
     sample_line=str(sample_time)+','+str(sample_value) 
     outfile.write(sample_line) 
     print 'time: ',sample_time,', value: ',sample_value 
+0

Zrobiłem tego rodzaju rzeczy przed użyciem/dev/rtc jako wyzwalacz w asynchronicznym reaktorze. Wyzwala w precyzyjnych odstępach czasu niezależnie od czasu pomiaru. Ale możesz też po prostu użyć itimeru. – Keith

Odpowiedz

8

Wystarczy zmierzyć czas uruchomiony kod wykonuje każdej iteracji pętli, a sleep odpowiednio:

import time 

while True: 
    now = time.time()   # get the time 
    do_something()    # do your stuff 
    elapsed = time.time() - now # how long was it running? 
    time.sleep(1.-elapsed)  # sleep accordingly so the full iteration takes 1 second 

Oczywiście nie w 100% doskonały (może poza jedną milisekundę lub inny od czasu do czasu) , ale myślę, że to wystarczająco dobre.


Kolejną miłą podejście wykorzystuje twisted „s LoopingCall:

from twisted.internet import task 
from twisted.internet import reactor 

def do_something(): 
    pass # do your work here 

task.LoopingCall(do_something).start(1.0) 
reactor.run() 
1

Na początku pętli sprawdź, czy upłynął odpowiedni czas. Jeśli nie, continue.

# Set up initial conditions for sample_time outside the loop 
sample_period = ??? 
next_min_time = 0 
while True: 
    sample_time=time.time()-zero 
    if sample_time < next_min_time: 
     continue 
    #read and print a line 
    sample_value=ser.readline() 
    sample_line=str(sample_time)+','+str(sample_value) 
    outfile.write(sample_line) 
    print 'time: ',sample_time,', value: ',sample_value 
    next_min_time = sample_time + sample_period 
+2

Wypełniasz czas oczekiwania pustą pętlą. Zamiast tego użyj 'time.sleep()', aby umożliwić harmonogramowi wypełnienie czasu oczekiwania przy przetwarzaniu innych wątków/procesów. –

1

raczej elegancka metoda pracujesz na systemie UNIX: korzystania z biblioteki sygnału

Kod:

import signal 


def _handle_timeout(): 
    print "timeout hit" # Do nothing here 

def second(count): 
    signal.signal(signal.SIGALRM, _handle_timeout) 
    signal.alarm(1) 
    try: 
     count += 1 # put your function here 
     signal.pause() 

    finally: 
     signal.alarm(0) 
     return count 


if __name__ == '__main__': 

    count = 0 
    count = second(count) 
    count = second(count) 
    count = second(count) 
    count = second(count) 
    count = second(count) 

    print count 

A czas:

[email protected]:~/Bureau$ time python timer.py 
5 

real 0m5.081s 
user 0m0.068s 
sys 0m0.004s 

Dwa zastrzeżenia: działa tylko na * nix i nie jest bezpieczny dla wielu aplikacji.

Powiązane problemy