Schrift
[thread]8902[/thread]

Spreadsheet::WriteExcel Spreadsheet::ParseExcel: Resourcenverwendung?

Leser: 10


<< |< 1 2 3 >| >> 22 Einträge, 3 Seiten
GoodFella
 2007-04-04 02:24
#75645 #75645
User since
2007-01-09
192 Artikel
BenutzerIn
[default_avatar]
Nach 5 Monaten Arbeit, die ich auf das Programmieren eines auf Spreadsheet::WriteExcel und Spreadsheet::ParseExcel basierenden Tools verwandt habe, ist mir jetzt beim betatesten der enorme Speicherverbrauch aufgefallen.

Zum Testen las ich eine 46.000 Zeilen x 20 Spalten lange Exceltabelle ein und speicherte diese sogleich wieder, ohne die Daten zusätzlich in einem Perl-Array zu haben.
Das fras 1,05 GigaByte Arbeitsspeicher. Das System war ausserdem 30min lang nicht mehr richtig ansprechbar, dann jedoch hatte es die Datei gespeichert, waren 19MB, naja, schon gross für eine Exceldatei, allerdings kann Excel ja bis zu 65.500 Datensätze.

Als ich mir dann mal angesehen habe, wie es mit der Validität des Inhalts steht, hab ich echt Angst bekommen, das ganze umsonst programmiert zu haben: So in ca. Zeile 7000 stehen komische Umbrüche, dann Daten aus den nächsten Spalten, dann eine Leerspalte, dann wieder normale Daten (im Vergleich zu den Originaldaten, wo alles stimmt).
Das tritt zum Glück nicht bei Dateien kleiner als (geschätzt) 32.000 Zeilen auf, ist einfach die Anzahl an Datensätzen, bei dem per try & error alles noch gestimmt hat.

Achja, Windows hat eine Warning wegen zu wenig virtuellem Arbeitsspeicher, der vergrössert wird, ausgegeben.

Jetzt zu meinen Fragen:

1. Wie kann ich den Speicherverbrauch minimieren? (Ich weiss, das Ding benutzt Storage_Lite, also muss es daran liegen?)
2. Hat jemand schonmal Datenmüll mit diesen Modulen bekommen? Also Datenmüll, der ausschliesslich von diesen Modulen produziert wurde, wie in meinem Fall das Excel-Format nicht eingehalten wurde für ein paar Datensätze mittendrin.

Umsteigen auf Win32::OLE ist schon insofern vorbereitet, als dass ich jegliches Lesen/Schreiben mit zentralen Funktionen mache; allerdings hätte ich lieber etwas OpenOffice-kompatibles.

Gruss

Pete
ptk
 2007-04-04 03:25
#75646 #75646
User since
2003-11-28
3645 Artikel
ModeratorIn
[default_avatar]
CSV?
GoodFella
 2007-04-04 03:30
#75647 #75647
User since
2007-01-09
192 Artikel
BenutzerIn
[default_avatar]
[quote=ptk,04.04.2007, 01:25]CSV?[/quote]
öhhhmm... da komme ich jetzt nicht so ganz mit ^^

Naja, vielleicht habe ich zu wenige Informationen gegeben..
Die Daten kommen als csv oder xls an, werden bearbeitet und MÜSSEN dann im Excelformat vorliegen; wobei Formate mitgespeichert werden müssen (Beispiel: Wenn Kommazahl Integer-Charakter aufweist, dann speichere als Format "#", ansonsten "#.##", die von der IDEAL wollen das so haben in bestimmten Formularen, die wir drucken)
GoodFella
 2007-04-06 08:35
#75648 #75648
User since
2007-01-09
192 Artikel
BenutzerIn
[default_avatar]
Habe mal ein paar mehr Infos zusammengetragen:
1. So sieht der Datenmüll aus: http://flux.pldsecurity.de/dm.jpg

2. zu Hause verursacht dieselbe Datei ~400MB weniger Speicherverbrauch, trotz gleicher Perl- und Modulversionen. Hier ist Spreadsheet::ParseExcel der Speicherfresser.
Eine 47.000x10-Zeilen-Datei braucht hier ca.500MB Speicher.. MS Excel braucht für dieselbe Datei nur 25-40MB.
Ein Ansatz wäre, Spreadsheet::ParseExcel zu sagen, es soll nur Rohdaten in den Speicher laden und keine Formate/Formeln/etc.
..Allerdings wäre eine Speicherung in einem C-Array oder etwas in der Art wünschenswerter, da weniger Speicher + performanter.

Bin für jegliche weiterführende Ideen dankbar..
GoodFella
 2007-04-08 17:24
#75649 #75649
User since
2007-01-09
192 Artikel
BenutzerIn
[default_avatar]
Es bleibt mir ja nur der Umstieg auf Win32::OLE, also habe ich mal einen Geschwindigkeitstest gemacht:
Code (perl): (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#!/usr/bin/perl

use strict;
use warnings;

use Win32::OLE;
use Win32::OLE::Const 'Microsoft Excel';

my $xl = Win32::OLE->GetActiveObject('Excel.Application') || Win32::OLE->new('Excel.Application', 'Quit'); 
$xl->{'Visible'} = 0;
$xl->{'DisplayAlerts'} = 0;   

my $book = $xl->Workbooks->Open('c:\test.xls');
my $sheet = $book->Worksheets(1);

my $last_row = $sheet->UsedRange->Find( { What => "*",
               
               
            SearchDirection => xlPrevious,
               
               
            SearchOrder => xlByRows } )->{Row};

print "Start Speed Test..\n";
my $current_time = time;
my $time_start = $current_time;

foreach my $y (1..$last_row)
 {
  foreach my $x ('a'..'j')
   {
    my $bla = $sheet->Range($x.$y)->{Value};
   }
  if ((time - $current_time) >= 1)
   {
    $current_time = time;
    my $speed = sprintf("%.2f", ($y / ($current_time - $time_start)));
    print "$speed Zeilen pro Sekunde\n" unless (($current_time - $time_start) == 0);
   } 
 }

$xl->Workbooks->Quit();
$xl->destroy();


Ergebnis: Die Geschwindigkeit pendelt sich bei ~90 Zeilen pro Sekunde ein. Das finde ich komisch, denn mit Spreadsheet::ParseExcel bekomme ich ~150 Zeilen pro Sekunde und wenn ich mir so manche VBA-Makros anschaue, dann sind die EXTREM viel schneller, obwohl Win32::OLE Excel ja genau wie VBA direkt benutzt...
Vielleicht ist da irgendein Engpass in meinem Code, den ich übersehen habe?

Nach DProf sieht es so aus, als wäre es wohl doch Win32::OLE ->

Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
%Time ExclSec CumulS #Calls sec/call Csec/c  Name
0.00 9.218 9.642 56101 0.0002 0.0002 Win32::OLE::Dispatch
0.00 5.943 5.943 168296 0.0000 0.0000 Win32::OLE::Tie::Fetch
0.00 3.512 4.071 56098 0.0001 0.0001 Win32::OLE::DESTROY
0.00 2.370 12.488 56101 0.0000 0.0002 Win32::OLE::AUTOLOAD
0.00 1.962 7.905 168296 0.0000 0.0000 Win32::OLE::Tie::FETCH
0.00 0.476 0.476 56102 0.0000 0.0000 UNIVERSAL::isa
0.00 0.223 0.223 56098 0.0000 0.0000 Win32::OLE::Tie::DESTROY
0.00 0.219 0.357 1 0.2191 0.3572 Win32::OLE::Const::_Typelibs
0.00 0.138 0.138 564 0.0002 0.0002 Win32::OLE::Const::_Typelib
0.00 0.030 0.046 4 0.0075 0.0115 Config::BEGIN
0.00 0.016 0.016 1 0.0160 0.0160 Win32::OLE::Const::_Constants
0.00 0.016 0.016 2 0.0080 0.0080 Exporter::as_heavy
0.00 0.016 0.016 6 0.0027 0.0026 ActiveState::Path::BEGIN
0.00 0.015 0.450 5 0.0030 0.0899 main::BEGIN
0.00 0.000 0.000 1 0.0000 0.0000 Config::launcher


..hätte eigentlich erwartet, dass das mit Win32::OLE schneller ist.
GoodFella
 2007-04-08 20:41
#75650 #75650
User since
2007-01-09
192 Artikel
BenutzerIn
[default_avatar]
tjo, bleibt wohl beim Selbstgespräch ^_^ ..
Würde mich trotzdem über wenigstens eine Meinung freuen..
PerlProfi
 2007-04-08 22:12
#75651 #75651
User since
2006-11-29
340 Artikel
BenutzerIn
[default_avatar]
Vielleicht ist folgende Seite für dich ganz interessant:
http://perlmonks.org/index.p....=379743

Der Artikel erklärt deine Probleme und stellt Lösungen vor.

Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/usr/bin/perl -w
use strict;
use Spreadsheet::ParseExcel;

my $parse_excel = Spreadsheet::ParseExcel->new(
CellHandler => \&cell_handler,
NotSetCell => 1,
);

my $workbook = $parse_excel->Parse('file.xls');

sub cell_handler {
my($workbook, $sheet_index, $row, $col, $cell) = @_;

# Skip some worksheets and rows (more efficiently).
if ($sheet_index > 2 and $row > 9) {
$workbook->ParseAbort(1);
return;
}

# Do something with the formatted cell value
print $cell->{_Value}, "\n";
}

^ letztes Beispiel aus dem Artikel

MfG\n\n

<!--EDIT|PerlProfi|1176056320-->
ptk
 2007-04-09 00:56
#75652 #75652
User since
2003-11-28
3645 Artikel
ModeratorIn
[default_avatar]
Ich kenne die Interna von Win32::OLE nicht, aber vielleicht kannst du alternative Aufrufmethoden verwenden, um die ganzen Tie-Aufrufe zu vermeiden? Tie ist nicht besonders effizient in Perl implementiert.
GoodFella
 2007-04-09 15:52
#75653 #75653
User since
2007-01-09
192 Artikel
BenutzerIn
[default_avatar]
[quote=ptk,08.04.2007, 22:56]Ich kenne die Interna von Win32::OLE nicht, aber vielleicht kannst du alternative Aufrufmethoden verwenden, um die ganzen Tie-Aufrufe zu vermeiden? Tie ist nicht besonders effizient in Perl implementiert.[/quote]
Tut mir leid, aber da habe ich nichtmal einen Ansatz, wie ich das umsetzen könnte, was du vorschlägst.

Ich habe aber Fortschritte gemacht, was Spreadsheet::ParseExcel betrofft, lies mal hier: http://www.perlmonks.org/index.pl?node_id=379743

..habe ich nach 3 Stunden suchen endlich was gefunden, was zutrifft. Leider wird es etwas dauern, das anzuwenden, denn ich habe keine Ahnung, wie das funktionieren soll. Ich habe dann halt diesen alternativen Cell-Handler; der wird aufgerufen, wenn eine Zelle in der Datei gefunden wird, und das bei jeder Zelle ausser leeren (wegen der Var, die auf 1 gesetzt wird) .. und wie habe ich Einfluss darauf, was davon gespeichert wird? oder soll ich selbst die Datenstruktur bauen? Das wär sehr schlecht, denn ich benutze die Datenstruktur schon das ganze mittlerweile 4600-Zeilen grosse Script durch. Werde mal ein paar Tests machen, wär aber leichter, wenn ich eure Meinung dazu hören würde, muss heute noch eine Präsentation darüber fertigstellen (morgen muss ich die halten) + den Code so fixen, dass er keine Speicherprobleme mehr macht. Eine fast unlösbare Aufgabe ^^ .. habe schon ganz Ostern dafür verschwendet :/
..Achja und danke, dass du meinen Monolog mit etwas Farbe gefüllt hast ^^

Gruss

Pete
PerlProfi
 2007-04-09 16:42
#75654 #75654
User since
2006-11-29
340 Artikel
BenutzerIn
[default_avatar]
Hast du mien Antwort überlesen ?
Quote
Vielleicht ist folgende Seite für dich ganz interessant:
http://perlmonks.org/index.p....=379743

Der Artikel erklärt deine Probleme und stellt Lösungen vor.

Code
#!/usr/bin/perl -w
use strict;
use Spreadsheet::ParseExcel;

my $parse_excel = Spreadsheet::ParseExcel->new(
CellHandler => \&cell_handler,
NotSetCell => 1,
);

my $workbook = $parse_excel->Parse('file.xls');

sub cell_handler {
my($workbook, $sheet_index, $row, $col, $cell) = @_;

# Skip some worksheets and rows (more efficiently).
if ($sheet_index > 2 and $row > 9) {
$workbook->ParseAbort(1);
return;
}

# Do something with the formatted cell value
print $cell->{_Value}, "\n";
}

^ letztes Beispiel aus dem Artikel

MfG


Und ja, so wie ich es verstanden habe sollst du die Datenstruktur dann selbst bauen.

MfG
<< |< 1 2 3 >| >> 22 Einträge, 3 Seiten



View all threads created 2007-04-04 02:24.