Come implementare l'elaborazione di un array con precisione millisecondo utilizzando python in linux (in esecuzione su un singolo core Raspberry Pi).Elaborazione del sub millisecondo in python senza busywait
Sto tentando di analizzare le informazioni da un file MIDI, che è stato pre-elaborato su un array in cui ogni millisecondo controllo se l'array ha voci al timestamp corrente e attiva alcune funzioni se lo fa.
Attualmente sto utilizzando time.time() e impieghiamo l'attesa di occupato (come concluso here). Questo mangia tutta la CPU, quindi opto per una soluzione migliore.
# iterate through all milliseconds
for current_ms in xrange(0, last+1):
start = time()
# check if events are to be processed
try:
events = allEvents[current_ms]
# iterate over all events for this millisecond
for event in events:
# check if event contains note information
if 'note' in event:
# check if mapping to pin exists
if event['note'] in mapping:
pin = mapping[event['note']]
# check if event contains on/off information
if 'mode' in event:
if event['mode'] == 0:
pin_off(pin)
elif event['mode'] == 1:
pin_on(pin)
else:
debug("unknown mode in event:"+event)
else:
debug("no mapping for note:" + event['note'])
except:
pass
end = time()
# fill the rest of the millisecond
while (end-start) < (1.0/(1000.0)):
end = time()
dove last
è il millisecondo dell'ultimo evento (noto dalla pre-elaborazione)
Questa non è una domanda circa time() vs clock() più su sleep vs busy wait.
Non riesco a dormire nel ciclo di "riempimento resto di millisecondo", a causa dello too lowaccuracy of sleep(). Se dovessi usare ctypes, come faccio a farlo correttamente?
C'è qualche libreria Timer che richiama in modo affidabile un callback ogni millisecondo?
La mia attuale implementazione è GitHub. Con questo approccio ottengo un disallineamento di circa 4 o 5ms sul drum_sample, che è 3.7s totale (con finto, quindi nessun hardware reale collegato). Su un campione 30.7s, l'inclinazione è di circa 32 ms (quindi almeno non lineare!).
Ho provato con time.sleep() e nanosleep() via ctypes con il seguente codice
import time
import timeit
import ctypes
libc = ctypes.CDLL('libc.so.6')
class Timespec(ctypes.Structure):
""" timespec struct for nanosleep, see:
http://linux.die.net/man/2/nanosleep """
_fields_ = [('tv_sec', ctypes.c_long),
('tv_nsec', ctypes.c_long)]
libc.nanosleep.argtypes = [ctypes.POINTER(Timespec),
ctypes.POINTER(Timespec)]
nanosleep_req = Timespec()
nanosleep_rem = Timespec()
def nsleep(us):
#print('nsleep: {0:.9f}'.format(us))
""" Delay microseconds with libc nanosleep() using ctypes. """
if (us >= 1000000):
sec = us/1000000
us %= 1000000
else: sec = 0
nanosleep_req.tv_sec = sec
nanosleep_req.tv_nsec = int(us * 1000)
libc.nanosleep(nanosleep_req, nanosleep_rem)
LOOPS = 10000
def do_sleep(min_sleep):
#print('try: {0:.9f}'.format(min_sleep))
total = 0.0
for i in xrange(0, LOOPS):
start = timeit.default_timer()
nsleep(min_sleep*1000*1000)
#time.sleep(min_sleep)
end = timeit.default_timer()
total += end - start
return (total/LOOPS)
iterations = 5
iteration = 1
min_sleep = 0.001
result = None
while True:
result = do_sleep(min_sleep)
#print('res: {0:.9f}'.format(result))
if result > 1.5 * min_sleep:
if iteration > iterations:
break
else:
min_sleep = result
iteration += 1
else:
min_sleep /= 2.0
print('FIN: {0:.9f}'.format(result))
Il risultato sulla mia i5 è
FIN: 0,000165443
mentre sul RPI è
FIN: 0,000578617
che suggeriscono un periodo di sonno di circa 0,1 o 0,5 millisecondi, con il dato jitter (tendono a dormire più a lungo), che al massimo mi aiuta a ridurre il carico un po '.
Hai provato a utilizzare 'sleep()' o a testarne le prestazioni sul tuo sistema? [La seconda risposta] (http://stackoverflow.com/a/15967564/3004881) dopo quella collegata indica che potrebbe avere una precisione più che sufficiente per te. –
sì ho fatto (vedi domanda aggiornata), e il link suggerisce tempi di sonno oltre 1ms, sto cercando soluzioni di seguito (dal momento che 1ms sarà molto probabilmente superato). Non riesci a verificare l'accuratezza di 1μs, quindi forse ancora dormendo bene e la misurazione è appena fuori? – x29a
È necessario sapere che se si utilizza un'interfaccia MIDI convenzionale, è necessario 1 ms per trasmettere un messaggio "nota su" singolo (3 ottetti). Potresti cercare una precisione che lo strumento non può soddisfare. – msw