Seite 1 von 1

Vereinfachung gesucht

Verfasst: Montag 21. Dezember 2009, 14:20
von mathi
Für folgenden Schnipsel suche ich eine Vereinfachung,

wichtig ist, dass with open() weil die Dateien nach der Bearbeitung gelöscht werden sollen.
die Anzahl der Dateien

Code: Alles auswählen

dokument0.pdf
sind von der Größe von cores abhängig.

Das ganze sollte erweiterbar sein von cores=1 ... 8.

http://paste.pocoo.org/show/qMiEc9vrrlmcsO4IoEOQ/

Ich finde das mit

Code: Alles auswählen

if cores==1...
usw. irgendwie ungeschickt, auch wenn es funktioniert

Gruß Mathi

Verfasst: Montag 21. Dezember 2009, 14:36
von Defnull
Und da bist du nicht selbst drauf gekommen?

Code: Alles auswählen

for c in len(cores):
  with open(self.tempdir+'\\document%d.pdf' % c, "rb") as doc:
    pdf = PdfFileReader(doc)
    for page in pdf.pages:
      ...
Das mit den cores wird dir aber nix bringen, wenn du nur einen Python Prozess startest.

Verfasst: Montag 21. Dezember 2009, 14:36
von jbs
Ungetestet:

Code: Alles auswählen

files = [os.path.join(self.tempdir, 'document{i}.pdf'.format(i=i)) for i in range(cores)]

pdfs = []
for f in files:
    with open(f) as fobj:
        pdfs.append(PdfFileReader(fobj))

Verfasst: Montag 21. Dezember 2009, 15:03
von mathi
Danke für Eure Antworten

@Defnull

wie kommst Du darauf, dass ich nur einen Prozess starte?
Jeder Prozess läuft auf einem CPU-Kern und liefert ein dokument_.pdf.
Deine Lösung funktioniert nicht, weil nur eine .pdf geöffnet wird.
Dass ich

Code: Alles auswählen

for nr in xrange(cores): 
            part=self.tempdir+'\\document%s.pdf' % nr
            inputs.append(PdfFileReader(file(part, "rb")))
schreiben kann, weiß ich, bringt nur nix, weil die .pdf nach beenden des Programmes noch vom System geöffnet sind und nicht gelöscht werden können.

@jbs
Dein Vorschlag iteriert über files,
nach dem ersten Durchlauf wird die erste Datei aber wieder geschlossen :-(
es müssen aber gleichzeitig alle .pdf geöffnet sein, damit der Rest funktionieren kann

Code: Alles auswählen

output.write(temp_file)
funktioniert nur, wenn alle relevaten .pdf gleichzeitig geöffnet sind

Verfasst: Montag 21. Dezember 2009, 15:35
von Dav1d
mathi hat geschrieben:

Code: Alles auswählen

for nr in xrange(cores): 
            part=self.tempdir+'\\document%s.pdf' % nr
            inputs.append(PdfFileReader(file(part, "rb")))
schreiben kann, weiß ich, bringt nur nix, weil die .pdf nach beenden des Programmes noch vom System geöffnet sind und nicht gelöscht werden können.
Dann musst du die Datei in der For-Schleife öffnen und schließen, vorzugsweise "with" verwenden, ich seh da kein Problem, Defnull hats doch schon vorgemacht, wies gehen könnte/kann

Verfasst: Montag 21. Dezember 2009, 15:46
von HWK
Schau Dir mal contextlib.nested an.
MfG
HWK

Verfasst: Montag 21. Dezember 2009, 16:24
von mathi
vielleicht steh ich auf dem Schlauch, aber
jbs
hat ja schon nested() vorgeschlagen.

Der befehl ist meines Wissens nach nicht änderbar, ich meine damit:

Code: Alles auswählen

if cores==1:
    with nested.....
elif cores==2:
    with nested.... 
müßte ich dann schreiben, und genau dass wollte ich eben nicht...

@HWK
schau mal in meinen letzten Post unseres .pdf-Seitenzahlen-threads 8)
Das hier ist das letzte Problemchen, dann habe ich mein Programm erstellt :-)


Gruß
Mathi

Verfasst: Montag 21. Dezember 2009, 16:30
von HWK
mathi hat geschrieben:vielleicht steh ich auf dem Schlauch, aber
jbs
hat ja schon nested() vorgeschlagen.
Vielleicht steh ich auf dem Schlauch, aber wo denn?
Hier ein Beispiel, auf dem Du aufbauen kannst:

Code: Alles auswählen

>>> from contextlib import nested
>>> a = ['Test1', 'Test2']
>>> with nested(*(open(x, 'rb') for x in a)) as b:
	print b

	
[<open file 'Test1', mode 'rb' at 0x018F91B0>, <open file 'Test2', mode 'rb' at 0x018F9430>]
MfG
HWK

Verfasst: Montag 21. Dezember 2009, 16:46
von mathi
HWK hat geschrieben:
mathi hat geschrieben:vielleicht steh ich auf dem Schlauch, aber
jbs
hat ja schon nested() vorgeschlagen.
Vielleicht steh ich auf dem Schlauch, aber wo denn?
aaachh, hast recht, ich hatte seinen Vorschlag mit nested probiert und ihm das gleich mal angedichtet, Entschuldigung hast recht :oops:

Verfasst: Montag 21. Dezember 2009, 17:01
von mathi
@HWK

Mensch,
vielen Dank nochmal für Deine Geduld, jetzt hab ich es geschafft:

Code: Alles auswählen

        for nr in xrange(cores):
            pdfs.append(self.tempdir+'\\document%s.pdf' % nr)
        with nested(*(open(x, 'rb') for x in pdfs)) as pdflist: 
            for x in pdflist:
                file=PdfFileReader(x)
                for page in file.pages:
                    output.addPage(page)    
                    .........
            output.write(temp_file)
@all
übrigens Danke an alle, mal gaanz pauschal :-)


Gruß Mathi

Verfasst: Montag 21. Dezember 2009, 17:05
von Darii
Übrigens sollte man noch anmerken, dass solch naive Parallelisierung bei I/O-Zugriffen kontraproduktiv sein kann. Da I/O-Zugriffe meist sowieso nur seriell erfolgen kann das durchaus das ganze ausbremsen, wenn man trotzdem versucht 4 Dateien gleichzeitig zu lesen(dann langweilen sich nämlich alle 4 Prozessoren, während die 4 Dateien jeweils 4-Mal so langsam gelesen werden).

Verfasst: Montag 21. Dezember 2009, 17:14
von mathi
@Darii

siehe http://www.python-forum.de/topic-21172,45.html
letzter Post,

parallelisiert werden ganz andere Sachen, das hier ist nur die Endverarbeitung des Ergebnisses, welche auf einem Kern läuft :-)

Verfasst: Montag 21. Dezember 2009, 21:06
von mathi
eine kurze frage habe ich noch,

warum ist das * in

Code: Alles auswählen

with nested(*(open(x, 'rb') for x in a)) as b:
notwendig, was wird damit bewirkt?? Dass es ohne nicht geht habe ich getestet.
Gruß
Mathi

Verfasst: Montag 21. Dezember 2009, 21:30
von cofi

Verfasst: Dienstag 22. Dezember 2009, 16:10
von mathi
Danke,

ich habe noch einen Fehler entdeckt, bei dem ich um Hilfe Bitte:

Code: Alles auswählen

        cores=cpu_count()  # Anzahl der Kerne

        teil=int(all_pages/cores) # Anzahl der Seiten, die je Kern zu bearbeiten sind

        processes=[
                   Process(target=merge, 
                           args=(teil,nr*teil,path,tempdir,nr)) 
                  for nr in xrange(cores)
                  ]
das dumme ist, dass dbei dieser lösung ein Rest bleibt.
Bsp:
cores=4 # Anzahl der Kerne
all_pages=141
teil=int(all_pages/cores) = int(141/4)=35 # Anzahl der Seiten, die je Kern zu bearbeiten sind
macht bei 4 Kernen 4*35=140 Seiten

das heißt, ich müßte eigendlich so etwas machen:

Code: Alles auswählen

        rest=all-(cores-1)*teil
        first=(cores-1)*teil
        kerne=cores-1
        processes=[
                   Process(target=merge, 
                           args=(teil,nr*teil,path,tempdir,nr)) 
                  for nr in xrange(kerne),
                  Process(target=merge, 
                           args=(rest,first,path,tempdir,kerne)) 
                  ]
So funktioniert es aber nicht.

Code: Alles auswählen

TypeError: unsupported operand type(s) for *: 'xrange' and 'int'
so funkktionierts natürlich für 4 Kerne:

Code: Alles auswählen

        processes=[
                   Process(target=merge, 
                           args=(teil,0*teil,path,tempdir,0)), 
                   Process(target=merge, 
                           args=(teil,1*teil,path,tempdir,1)), 
                   Process(target=merge, 
                           args=(teil,2*teil,path,tempdir,2)), 
                   Process(target=merge, 
                           args=(rest,3*teil,path,tempdir,3))
                  ]
Könnt Ihr mir helfen??

Gruß Mathi

Verfasst: Dienstag 22. Dezember 2009, 17:06
von EyDu
Der Modulo-Operator ist dein Freund.

Verfasst: Dienstag 22. Dezember 2009, 19:06
von mathi
Danke,

mir ist eine einfache Lösung auf dem Heimweg eingefallen, die ich morgen gleichmal testen will:

Code: Alles auswählen

cores=cpu_count()  # Anzahl der Kerne 

        teil=int(all_pages/cores) # Anzahl der Seiten, die je Kern zu bearbeiten sind 
        rest=all_pages-(cores-1)*teil)

        liste=(teil,teil,teil,rest)   # Beispiel für 4 Kerne, muß halt generiert werden

        processes=[ 
                   Process(target=merge, 
                           args=(liste[nr],nr*teil,path,tempdir,nr)) 
                  for nr in xrange(cores) 
                  ]
also falls das funktioniert, wäre es peinlich einfach :oops:


edit: es funktioniert,wirklich peinlich....
Gruß Mathi