2016-08-23 5 views
0

Diese Frage wurde viele Male auf SO gestellt (zum Beispiel here), aber es gibt noch keine echte Antwort.Wie kann die Python-Importgeschwindigkeit verbessert werden?

Ich schreibe ein kurzes Befehlszeilenprogramm, das Vorlagen rendert. Es wird mit einem Makefile frigged:

i = $(wildcard *.in) 
o = $(patsubst %.in, %.out, $(t)) 

all: $(o) 

%.out: %.in 
    ./script.py -o [email protected] $< 

In diesem Dummy Beispiel die Makefile analysiert jede .in Datei eine .out-Datei zu erzeugen. Es ist sehr praktisch für mich, make zu verwenden, da ich viele andere Aktionen vor und nach diesem Skript triggern muss. Darüber hinaus möchte ich so gerne wie möglich bleiben: KISS.

So will ich mein Werkzeug einfach halten, dumm und verarbeiten jede Datei separat mit der Syntax script -o out in

Mein Skript verwendet die folgenden:

#!/usr/bin/env python 
from jinja2 import Template, nodes 
from jinja2.ext import Extension 
import hiyapyco 
import argparse 
import re 

... 

Das Problem, dass jeder ist Ausführung kostet mich etwa 1,2s (~ 60ms für die Verarbeitung und ~ 1140ms für die Import-Richtlinien):

$ time ./script.py -o foo.out foo.in 
real 0m1.625s 
user 0m0.452s 
sys  0m1.185s 

Die Gesamtausführung meines Makefile für 100 Dateien ist lächerlich: ~ 100 Dateien x 1.2s = 120s.

Dies ist keine Lösung, aber dies sollte die Lösung sein.

Welche Alternative kann ich verwenden?

EDIT

ich Python lieben, weil seine Syntax lesbar und Größe der Gemeinde. In diesem speziellen Fall (Befehlszeilentools) muss ich zugeben, dass Perl immer noch eine gute Alternative ist. Das gleiche in Perl geschriebene Skript (das auch eine interpretierte Sprache ist) ist etwa 12 mal schneller (unter Verwendung von Text::Xslate).

Ich möchte nicht Perl in jedem Fall fördern Ich versuche nur, mein größtes Problem mit Python zu lösen: Es ist noch nicht eine geeignete Sprache für einfache Befehlszeilenwerkzeuge wegen der schlechten Importzeit.

+0

Dies wäre eine bessere Passform auf [Code Review] (http://codereview.stackexchange.com/) Solange Sie ein voll funktionsfähiges Beispiel haben – muddyfish

+0

@muddyfish Dies ist keine Code Review-Frage, da dies jedes in Python geschriebene CLI-Tool betreffen kann. – nowox

+0

Keine Lösung für die Frage, aber wie wäre es, die Dinge für Anfänger parallel zu machen? Könnte dein Problem lösen. –

Antwort

3

Es importieren ist nicht ganz einfach, aber Sie könnten Ihr Programm in eine Umdrehung, die im Hintergrund sitzt und Prozesse Befehle ein verarbeiten Datei.

Ein anderes Programm könnte ihm die Verarbeitungsbefehle zuführen und damit den eigentlichen Start recht einfach machen.

+1

Ich denke, das ist wahrscheinlich die vernünftigste Lösung, weil ich nicht denke, es gibt einen guten Weg, um den Modul-Import zu beschleunigen. –

0

Sie könnten glob verwenden, um diese Aktionen mit den benötigten Dateien auszuführen.

import glob 
in_files=glob.glob('*.in') 
out_files=glob.glob('*.out') 

So bearbeiten Sie alle Dateien im selben Skript, anstatt das Skript mit jedem Paar von Dateien jedes Mal aufzurufen. Auf diese Weise müssen Sie Python nicht jedes Mal neu starten.

+1

Sie beantworten nicht wirklich die Frage – nowox

+0

Es ist nur eine Problemumgehung, die ich verwende, wenn ich viele Dateien behandeln muss. Wenn Sie Ihr Skript jedes Mal aufrufen und Bibliotheken laden, wird es natürlich n-mal dauern, da es die Anzahl der zu verarbeitenden Dateien ist. – silgon

0

Es scheint ziemlich klar, wo das Problem ist, jetzt du hast:

cost(file) = 1.2s = 60ms + 1040ms, was bedeutet:

cost(N*files) = N*1.2s

jetzt, warum Sie es nicht ändern werden:

cost1(files) = 1040ms + N*60ms

so würde theorisch Verarbeitung 100 Dateien 7,04s statt 120s

EDIT:

Weil ich downvotes auf diese Frage bin empfangen, werde ich ein kleines Beispiel veröffentlichen, nehmen wir an, Sie das Python-Datei bekommen:

# foo.py 
import numpy 
import cv2 

print sys.argv[0] 

Die Ausführungszeit ist 1,3 s auf meiner Box, jetzt, wenn ich tun:

for /l %x in (1, 1, 100) do python foo.py 

ich werde 100 * 1,3 s Ausführungszeit erhalten, wurde mein Vorschlag foo.py in diese drehen:

import numpy 
import cv2 

def whatever_rendering_you_want_to_do(file): 
    pass 

for file in sys.argv: 
    whatever_rendering_you_want_to_do(file) 

diese Weise können Sie nur einmal statt 100 mal

+0

Genau, Sie haben darauf hingewiesen, wo das Problem liegt. Also meine Frage "Wie kann ich die Python-Importgeschwindigkeit verbessern?" – nowox

+0

@nowox Ich habe meine Antwort bearbeitet, hoffe, dass es hilft, weiß nicht, warum die Leute vorher abwarteten, ich dachte, das Problem sei per se eine gültige Antwort. – BPL

+0

Ich verstehe Ihre Antwort und das ist vielleicht eine gute Lösung für eine andere Frage, aber nicht diese besondere. Ich möchte die for-Schleife in meinem Python-Skript nicht machen. – nowox

1

Schreiben Sie den Vorlageteil als separaten Prozess. Wenn "script.py" zum ersten Mal ausgeführt wird, wird dieser separate Prozess gestartet. Sobald der Prozess existiert, kann er die Eingabe-/Ausgabedateinamen über eine Named Pipe übergeben. Wenn der Prozess für x Sekunden keine Eingaben erhält, wird er automatisch beendet. Wie groß x ist hängt davon ab, was Ihre Bedürfnisse sind

So werden die Parameter an den lang laufenden Prozess über die script.py Schreiben in eine Named Pipe übergeben. Die Importe kommen nur einmal vor (vorausgesetzt, die Inputs sind ziemlich oft) und wie BPL darauf hinweist, würde dies alles schneller laufen lassen.

+0

Können Sie ein funktionierendes Beispiel mit meinem Makefile bereitstellen? – nowox

Verwandte Themen