Perl Zugriff auf Array in Sub erzeugt Duplikate bei Mehrfachladen

furryhamster

Lt. Commander
Registriert
Okt. 2008
Beiträge
1.101
Hi,

mittels der Printfunktion in Perl erzeuge ich eine HTML Seite.
Eine Subfunktion wertet ein Array aus. Durch eine Schleife lese ich die Werte aus und gebe Sie aus. Doch jedes mal wenn ich schnell hintereinader F5 drücke erhalte ich dublikate des Arrays. Warte ich eine Minute und lade dann neu, so seht der Inhalt des Arrays wieder nur 1x dort:

Code sieht etwa wie folgt aus:
Code:
sub subfunktion ($) {
my @array = @{$_[0]};

$counter = 0;
while ($counter < @array) {
  print "$array[$counter]";
  $counter = $counter+1;
}
 
Logisch. Ein Workaround wäre:
Nimm dir eine globale Variable (0,1). Setze die beim Start der sub = 1 und bau dir eine Abfrage um die Schleife, so dass die nur läuft wenn deine globale = 0 ist.
Am Ende der sub halt wieder auf 0 resetten...
 
mhhh kannst du mir erklären warum das logisch ist. Ich verstehe das leider noch nicht.
auch funktioniert (zumindest mein Ansatz) noch nicht das Einbauen der globalen Variable. Da ich mich nicht gut mit perl auskenne aber wahrscheinlich fehler meinerseits. Auch nehme ich an, dass ich die globale am anfang auf 0 setzen soll und am ende auf 1.

Code sieht derzeit so aus:

subs.pm
Code:
our $global;

sub subfunktion ($) {
my @array = @{$_[0]};

$global = 0;

$counter = 0;
if ($global == 0) {
while ($counter < @array) {
  print "$array[$counter]";
  $counter = $counter+1;
}
}

$global = 1;

haupt.pl
Code:
subs::subfunktion(\@array);
 
Zuletzt bearbeitet:
Macht auch mega keinen Sinn was ich da geschrieben hab. Dann läuft die Schleife ja nie ... Zu früh =)
Mit dem Ansatz müsstest du die globale beim Methodenaufruf abfragen... Was dann in worten sowas gibt, wie "starte sie nur, wenn sie nicht gerade läuft".

Dein Problem scheint doch zu sein, dass die Methode mehrfach gleichzeitig laufen kann...

Also sowas wie:

sub xy{
$laeuft = 1;

#routine

$laeuft = 0;
}

und beim aufruf:

if($laeuft=0){xy()}
 
Zuletzt bearbeitet:
ich glaube nicht das die methode mehrfach läuft. ich habe mir jetzt noch mal den counter ausgeben lassen. Der inhalt des Arrays ist eigentlich 3. Wenn er die Werte aber durch neuladen der Seite mehrfach anzeigt, dann erhöht sich der counter auf > 3 und bei einem parallelem aufruf des arrays ändert sich ja nicht die arraygröße.
erhalte ich mit "$counter < @array" wirklich die korrekte arraygröße? eben hat er mit bei "print "@array" auch mal den inhalt ausgegeben.

Edit: so durch debugausgaben hab ich jetzt "bewiesen" das die größe des arrays wächst wenn ich das ganze mehrfach aufrufe. ich schau mal dass ich das Array gelöscht bekomme nach aufruf.
 
Zuletzt bearbeitet:
furryhamster schrieb:
ich glaube nicht das die methode mehrfach läuft. ich habe mir jetzt noch mal den counter ausgeben lassen. Der inhalt des Arrays ist eigentlich 3.
Du meinst die Länge?

furryhamster schrieb:
Wenn er die Werte aber durch neuladen der Seite mehrfach anzeigt, dann erhöht sich der counter auf > 3 und bei einem parallelem aufruf des arrays ändert sich ja nicht die arraygröße.
Stimmt. Dann liegt das Problem vermutlich woanders...

furryhamster schrieb:
erhalte ich mit "$counter < @array" wirklich die korrekte arraygröße? eben hat er mit bei "print "@array" auch mal den inhalt ausgegeben.
Das macht Perl kontextabhängig richtig. Innerhalb von "" wir der Array interpoliert... Allerdings kannst du eh besser mit foreach über einen Array iterieren. Der Counter ist unnötig.
 
ja genau, ich meine die Länge bzw die Anzahl der Elemente darin.

Beschäftige mich nicht so oft mit perl, daher wollte ich so auf nummer sicher gehen, auch zum debuggen.

Ich habe jetzt festgestellt, dass mit jedem aufruf die arraysize sich um 3 erhöht. Aufgrund der Ausgabe scheint er also den inhalt zu duplizieren. Ich habe daher versucht mit while (@array) {shift(@array) } das array zu löschen, leider ohne erfolg

Edit: kann der fehler bereits daran liegen: ich habe eine subfunktion, die das array returned und dieses übergebe ich mit \@array. Kann es dabei zu problemen kommen?
 
Zuletzt bearbeitet:
Zimon schrieb:
Dein Problem scheint doch zu sein, dass die Methode mehrfach gleichzeitig laufen kann...

Sorry, wenn ich mich hier mal mit meinem Halbwissen dazwischenschalte, aber wie meinst du das? Mir fallen nur 2 Möglichkeiten ein, wie die Funktion mehr als einmal "aktiv" sein kann:

  1. Rekursion ... aber laut furryhamsters Code ruft subfunktion weder sich selbst noch eine andere Funktion, die zu einer Rekursion von subfunktion führen könnte, auf.
  2. Multithreading.

Meinst du letzteres? Wenn ja, dann müßte furryhamster ja schnell klären können, ob er irgend einen Threading-Mechanismus nutzt, den meines Wissens arbeitet der Perl-Interpreter per Default nicht parallel.
Ergänzung ()

furryhamster schrieb:
Ich habe jetzt festgestellt, dass mit jedem aufruf die arraysize sich um 3 erhöht. Aufgrund der Ausgabe scheint er also den inhalt zu duplizieren. Ich habe daher versucht mit while (@array) {shift(@array) } das array zu löschen, leider ohne erfolg

Edit: kann der fehler bereits daran liegen: ich habe eine subfunktion, die das array returned und dieses übergebe ich mit \@array. Kann es dabei zu problemen kommen?

Zeig mal bitte den kompletten Code. Reduzier ihn aber vorher auf den kleinsten Umfang, der noch die von dir beschriebenen Symptome zeigt.
 
Nein, ich mache kein multihreading oder irgendwas, was parallele Verarbeitung ermöglichen würde (meines Wissens).

Code habe ich auf ein minimum reduziert und variablen umbenannt. Ich bin mitlerweile soweit, dass ich weiß, dass bei erneutem aufruf der holedaten sub das Array noch gefüllt ist und somit einfach die daten nochmal reingepusht werden

Code:
haupt.pl
#!/usr/bin/perl 

use funktionen;

@array = funktionen::holedaten($db, $kriterium, $xx, $yy);
funktionen::verarbeite($db, \@array);


funktionen.pm
package funktionen;

sub holedaten($$$$) {
	my ($dbh) = shift;
	my ($kriterium) = shift;
	my ($xx) = shift;
	my ($yy) = shift;

# DB zugriff und select
	$sth->execute();


	while ( my @data = $sth->fetchrow_array() )
	{
                push(@array, $data[0]);
	}

	return @array;
}

sub verarbeite($$) {
	my ($db) = shift;
	my @array= @{$_[0]};

	while ($counter < @konten) {
		print "arraygroesse: @konten";
		print "<br>$konten[$counter]";
		print "----$counter------";
		$counter = $counter+1;
	}
			while (@array) {
				print "loesche2";
				shift@array;
			}
}
 
Zuletzt bearbeitet:
Ich bin gerade bei der Analyse, aber soviel schon mal vorweg ... du solltest auf jeden Fall mit use strict; arbeiten.
Ergänzung ()

furryhamster schrieb:
Code habe ich auf ein minimum reduziert und variablen umbenannt. Ich bin mitlerweile soweit, dass ich weiß, dass bei erneutem aufruf der holedaten sub das Array noch gefüllt ist und somit einfach die daten nochmal reingepusht werden

Also mein Perl-Interpreter weigert sich, den Code, den du gepostet hast, überhaupt zu schlucken ... da sind diverse, grobe Syntax-Fehler drinnen. Wie gesagt, füge als erste 2 Zeilen in jedes deiner Skripte

Code:
use strict;
use warnings;

ein, und du wirst auf Anhieb von ganz allein weiterkommen.
 
Danke dass du es dir angeschaut hast.

Da das gesamtskript deutlich umfangreicher ist, war ich auch nicht davon ausgegangen das mein code so lauffähig wäre. dafür habe ich zu viel weggelassen.

das use strict werde ich mal einführen, das ist sicherlich sinnvoll, wird aber wahrscheinlich nicht das Problem lösen. Das Problem wird ein Zwischenspeicherproblem oder ähnliches sein. mittels undef habe ich das Array jetzt vor dem füllen gelöscht. Es werden die Daten jetzt zwar nicht mehr doppelt ausgegeben, allerdings wird das Array auch nur noch beim ersten aufruf oder nach ca 30 sec warten befüllt.
 
furryhamster schrieb:
das use strict werde ich mal einführen, das ist sicherlich sinnvoll, wird aber wahrscheinlich nicht das Problem lösen.

Da wäre ich mir gar nicht mal so sicher. Ohne use strict; werden (so weit ich weiß) zuvor nicht existente Variablen einfach so beim ersten Zugriff ins Leben gerufen, und ich weiß im Moment nicht mit welchem Gültigkeitsbereich. Sollten diese Variablen mit globaler Gültigkeit erstellt werden, könnte das deinen Programmablauf entscheidend verändern.

Ich würde sofort auf use strict; umsteigen und dann solange Fehler beheben, bis der Interpreter nicht mehr meckert. Möglichweise hat sich dein Problem damit schon erledigt.
 
Zuletzt bearbeitet:
Nach der initialisierung des counters geht es .... o_O VIELEN DANK!

Das use strict wollte ich jetzt aktivieren. Leider erhalte ich dann direkt Internal Server Error 500 ohne Angabe von Fehlern bzw Zeilenangaben. Bei ca 600 Zeilen ist es ja quasi fast unmöglich so alles zu deklarieren wo etwas fehlt :/ An das Log komme ich glaube nicht dran. Gibt es einen Trick wie er mir die betroffene Zeile im Browser anzeigt? use warnings; habe ich ebenfalls aktiviert
 
furryhamster schrieb:
Nach der initialisierung des counters geht es .... o_O VIELEN DANK!

Ah ja, jetzt wo du's sagst, macht das natürlich auch Sinn. :) Die $counter-Variable existierte zuerst nicht (du hattest sie nirgends deklariert) und wurde einfach beim ersten Zugriff implizit (und anscheinend tatsächlich mit globalem Scope) erstellt. Da sie nun global und eben nicht lokal war, behielt sie über die verschiedenen Aufrufe deiner verarbeite()-Funktion ihren Wert.

furryhamster schrieb:
Das use strict wollte ich jetzt aktivieren. Leider erhalte ich dann direkt Internal Server Error 500 ohne Angabe von Fehlern bzw Zeilenangaben. Bei ca 600 Zeilen ist es ja quasi fast unmöglich so alles zu deklarieren wo etwas fehlt :/

Wenn man das im Nachhinein tut, kann das natürlich ein Batzen Arbeit sein (lohnt sich aber meines Erachtens trotzdem ... danach bist du dann SAUBER).


furryhamster schrieb:
An das Log komme ich glaube nicht dran. Gibt es einen Trick wie er mir die betroffene Zeile im Browser anzeigt? use warnings; habe ich ebenfalls aktiviert

Hmm, da kann ich leider nicht helfen. Ich lasse Perl-Skripte immer nur direkt im Interpreter laufen ... von Web-Integration und solchem Zeugs habe ich keine Ahnung. :-\
Ergänzung ()

Könntest du dir eventuell ein kleines Testskript schreiben, das deine Funktionen alle mal mit mehr oder weniger sinnvollen Parametern aufruft? Dieses Skript könntest du dann vielleicht direkt auf der Kommandozeile laufen lassen und würdest damit auch die Stacktraces / Fehlermeldungen ins Shell-Fenster bekommen.
Geht natürlich nur, wenn deine Skripte nicht zu viele Abhängigkeiten zu irgendwelchen Web-Geschichten haben.
 
Zuletzt bearbeitet:
Ich habe mich nochmal informiert und kann jetzt auch im Log nachschauen wo es knallt. Bin gerade fleißig am deklarieren. Danke nochmals. Ab jetzt kein Perl mehr ohne use strict :)
 
Zurück
Oben