2012-05-02 15 views
5

Vorrei ottenere la temperatura di un disco rigido usando Python (sotto Linux). Attualmente sto chiamando hddtemp con subprocess.popen, ma lo chiamo abbastanza spesso che si tratta di un collo di bottiglia delle prestazioni nel mio script. Penso che dovrebbe essere possibile fare qualcosa di simile a question 4193514?Ottieni la temperatura del disco rigido usando Python

+3

Quanto spesso controlli la temperatura? Dovresti essere in grado di memorizzare il valore nella cache per un minuto circa. Non cambia molto velocemente. –

+4

@gnibbler: Ma come sarebbe in grado di misurare la circostanza di lanciare la macchina in un camino? – jdi

+0

È per una pagina Web che mostra lo stato del server in tempo reale. Quando la pagina è aperta, si aggiorna ogni 5-10 secondi circa. – lyineyes

risposta

5

È possibile eseguire hddtemp come demone (l'opzione -d), quindi utilizzare i socket per interrogare esso - il valore predefinito è la porta 7634. ​​

Edit: vedi some code that does this.

+0

Questo è esattamente quello che stavo cercando, grazie! Punti bonus per l'esempio di codice. – lyineyes

2

Espansione su ciò che @gnibbler ha suggerito nel suo commento principale, che ne è dell'approccio memorizzato nella cache? Questo è un esempio stupidamente semplice solo per mostrare il concetto:

from collection import defaultdict 

class CachedValue(object): 
    def __init__(self): 
     self.timestamp = -1 
     self._value = None 

    @property 
    def value(self): 
     return self._value 

    @value.setter 
    def value(self, val): 
     self._value = val 
     self.timestamp = time.time() 

    def isOld(self, seconds): 
     return (time.time() - self.timestamp) >= seconds 

>>> _cached = defaultdict(CachedValue) 
>>> _cached['hddtemp'].isOld(10) 
True 
>>> _cached['hddtemp'].value = 'Foo' 
>>> _cached['hddtemp'].isOld(10) 
False 
# (wait 10 seconds) 
>>> _cached['hddtemp'].isOld(10) 
True 

E nel tuo caso specifico:

def reportHDD(self): 
    if self._cached['hddtemp'].isOld(10): 
     self._cached['hddtemp'].value = self.getNewHDDValue() 
    return self._cached['hddtemp'].value 

Questo approccio è molto più di una soluzione generale per la memorizzazione nella cache un'operazione costosa. Nelle applicazioni più grandi, CachedValue potrebbe essere facilmente sostituito con una semplice ricerca memcached/redis che mantiene il proprio valore TTL per te. Ma su piccola scala, questo è solo un modo ingegnoso di organizzare i valori della cache locale.

+0

Ottimo esempio. Penso che userò questo per le altre funzioni, ma per ottenere la temperatura dell'harddrive, ho fatto ricorso alla generazione di un thread (per cercare di attenuare il sovraccarico della chiamata di sistema lenta) per aggiornare una voce dict. – lyineyes

+0

@lyineyes: Ma perché persino sostenere i costi generali sia in un thread o ovunque, se la temperatura può davvero solo fluttuare in un lasso di tempo ragionevole? Ma Hugh Bothwell menziona nella sua risposta che si può semplicemente monitorare la versione demonizzata di questo strumento in modo specifico. Quindi questa è probabilmente la tua soluzione specifica. Ma sono contento che ti sia piaciuto questo approccio per una soluzione di caching generale! – jdi

2

Stavo cercando su Google per un po 'e questo colpo continuava a venire vicino alla parte superiore, non importa quanto ho formattato la mia ricerca. Ho smartmontools e almeno python 2.7.6 installato su tutti i miei host e non volevo installare un nuovo pacchetto per il pipe dei dati temporanei di hdd su graphite/statsd quindi ho fatto quanto segue.

Io non sono uno sviluppatore e non conosco Python (come ovvio), quindi questo è il mio tentativo di 1-2 giorni di capirlo. Sono troppo imbarazzato per inviare tutto il codice qui, ma qui è la dealy principale ::

enter code here 
#!/usr/bin/env python 
import os 

import subprocess 

import multiprocessing 

def grab_hdd_temp(hdd, queue): 
    for line in subprocess.Popen(['smartctl', '-a', str('/dev/' + hdd)], stdout=subprocess.PIPE).stdout.read().split('\n'): 
    if ('Temperature_Celsius' in line.split()) or ('Temperature_Internal' in line.split()): 
     queue.put([hdd, line.split()[9]]) 

def hddtmp_dict(hdds_list): 
    procs = [] 
    queue = multiprocessing.Queue() 
    hddict={} 
    for hdd in hdds_list: 
    p = multiprocessing.Process(target=grab_hdd_temp, args=(hdd, queue)) 
    procs.append(p) 
    p.start() 
    for _ in procs: 
    val = queue.get() 
    hddict[val[0]]=val[1] 
    p.join() 
    return hddict 

if __name__ == '__main__': 
    hdds_list = [ x for x in os.listdir('/sys/block/') if x.startswith('sd') ] 
    hddict = hddtmp_dict(hdds_list) 
    for k in hddict: 
     print(k, hddict[k]) 

Sul mio server di archiviazione questo restituito l'elenco completo delle 38 unità in 2 secondi vs 50 secondi per scorrere tutte le dischi in serie. Detto questo, il carico salta da circa 1,08 a 3,50 su una cassa da 40 core. Quindi prendilo come vuoi Sto cercando di trovare un modo per utilizzare proc o possibilmente fcntl based on another stack overflow I found per estrarre i dati invece di usare subprocess.popen ma eh.

Sono le 2:22 e ho bisogno di iniziare a tornare a casa. Una volta lì cercherò di delineare il frammento sopra e di dire cosa penso che stia facendo tutto, ma spero che sia in qualche modo auto-esplicativo.

Ci scusiamo per il codice kludge. Penso che il buffer sia il modo migliore per andare a questo punto, ma è stato un esercizio interessante. Se non si desidera installare hddtemp e questo penso che un buffer + quanto sopra potrebbe essere l'opzione migliore. Sto ancora cercando di capirlo così come non capisco ancora come si fanno le classi.

Spero che questo aiuti qualcuno.

+0

Purtroppo sono attualmente sospeso da ServerFault per un anno, perché ho consigliato ai neofiti di usare il tasto Maiusc se iniziano una frase :-) – peterh

Problemi correlati