2013-03-18 15 views
6

Ho un framework composto da diversi strumenti scritti in python in un ambiente multiutente.Come velocizzare Python all'avvio e/o ridurre la ricerca di file durante il caricamento delle librerie?

La prima volta che accedo al sistema e avvio di un comando ci vogliono 6 secondi solo per mostrare alcune linee di aiuto. Se rilancio immediatamente lo stesso comando, occorrono 0,1 secondi. Dopo un paio di minuti torna a 6 secondi. (prova di cache di breve durata)

Il sistema si trova su un GPFS quindi il throughput del disco dovrebbe essere ok, sebbene l'accesso potrebbe essere basso a causa della quantità di file nel sistema.

strace -e open python tool | wc -l 

mostra 2154 file a cui si accede all'avvio dello strumento.

strace -e open python tool | grep ENOENT | wc -l 

mostra 1945 file mancanti ricercati. (Un pessimo rapporto hit/miss mi chiedi :-)

Ho l'impressione che il tempo eccessivo impiegato nel caricamento dello strumento venga consumato interrogando il GPFS su tutti quei file, e questi vengono memorizzati nella cache per il prossimo chiamata (a livello di sistema o GPFS), anche se non so come testarlo/dimostrarlo. Non ho accesso root al sistema e posso solo scrivere su GPFS e/tmp.

E 'possibile migliorare questo python quest for missing files?

Qualche idea su come testare questo in modo semplice? (Reinstallare tutto su/tmp non è semplice, dato che ci sono molti pacchetti coinvolti, virtualenv non sarà di aiuto neanche (credo), dal momento che è solo collegando i file sul sistema gpfs).

Un'opzione sarebbe ovviamente avere un daemon che si biforca, ma che è tutt'altro che "semplice" e sarebbe una soluzione di ultima istanza.

Grazie per la lettura.

risposta

2

Che ne dici di utilizzare il modulo imp? In particolare c'è una funzione: imp.find_module (modulo, percorso) qui http://docs.python.org/2.7/library/imp.html

Almeno questo esempio (vedi sotto) riduce il numero di open() chiamate di sistema vs semplice 'NumPy importazione, SciPy': (update: ma non sembra sia possibile per ottenere significative riduzioni di chiamate di sistema in questo modo ...)

import imp 
import sys 


def loadm(name, path): 
    fp, pathname, description = imp.find_module(name,[path]) 
    try: 
     _module = imp.load_module(name, fp, pathname, description) 
     return _module 
    finally: 
     # Since we may exit via an exception, close fp explicitly. 
     if fp: 
      fp.close() 


numpy = loadm("numpy", "/home/username/py-virtual27/lib/python2.7/site-packages/") 
scipy = loadm("scipy", "/home/username/py-virtual27/lib/python2.7/site-packages/") 

Credo anche meglio controllare che il vostro PYTHONPATH è vuota o piccolo, perché questo può anche aumentare il tempo di caricamento.

+0

Effettivamente ho provato questo e sembrava promettente, anche se tutte le librerie di default sono lanciate all'avvio e non posso dire a python da quale file deve caricare un modulo, ma lascialo cercarlo in una directory, causando 4 chiamate open() e almeno 2 miss. Spero solo che ci sia un modo per dire a Python di non farlo. – estani

2

Python 2 cerca prima i moduli rispetto al pacchetto corrente. Se il codice della libreria contiene molte importazioni per molti moduli di livello superiore, questi vengono prima considerati come relativi. Quindi, se il pacchetto foo.bar importa os, Python primo cerca foo/bar/os.py. Anche questa miss è memorizzata nella cache da Python stesso.

In Python 3, il valore predefinito è stato spostato in importazioni assolute; è possibile passare Python 2.5 e per l'utilizzo di importazioni assoluti per modulo con:

from __future__ import absolute_import 

Un'altra fonte di incidenti di ricerca di file sta caricando .pyc file di cache bytecode; se questi mancano per qualche motivo (il filesystem non è scrivibile per il processo Python corrente), Python continuerà a cercarli a ogni esecuzione. È possibile creare questi cache con il compileall module:

python -m compileall /path/to/directory/with/pythoncode 

a condizione che si esegue con i permessi di scrittura corrette.

+0

hmmm ... Ho provato questo nella chiamata di livello superiore (lo script che importa il resto), ma ha appena aggiunto altre 25 ricerche di file alla ricerca di __future__ senza alcun altro vantaggio: - /. Tutti .pyc ci sono, ma l'ordine di ricerca è sempre: '* .so -> * module.so -> * .py -> * .pyc', quindi non fa differenza. Dal modo in cui è absolute_import (no s). Grazie comunque! – estani

+0

corretto. Sì, immagino che Python debba cercare le estensioni C prima dei file Python, e dovrà trovare il file '.py' per verificare se il file' .pyc' è forse obsoleto. Stavo cercando di darti le opzioni per le ricerche che * possono * essere evitate. –

+0

Infatti, grazie per quello! L'ho anche testato con un file che carica solo os e prima di girare l'opzione '__future__' non ha fatto alcuna differenza. Penso di poter provare a sintonizzare PYTHONPATH, anche se mi piacerebbe che ci fosse un modo per memorizzare tutte le chiamate da una chiamata Python all'altra ... è possibile caricare un modulo in memoria da un determinato percorso? Forse potrei pre-caricarli ... – estani

Problemi correlati