2008-12-11 12 views
5

Ich habe ein Client-Server-Programm mit Perl mit IO :: Socket :: INET erstellt. Ich greife auf den Server über eine CGI-basierte Site zu. Mein Serverprogramm läuft als Daemon und akzeptiert mehrere gleichzeitige Verbindungen. Mein Serverprozess benötigt ca. 100 MB Speicherplatz (9 große Arrays, viele Arrays ...). Ich möchte diese Hashes im Speicher haben und sie teilen, so dass ich sie nicht für jede Verbindung erstellen muss. Hash-Erstellung dauert 10-15 Sekunden.Wie kann ich mehrere Sockets in einem Perl-Daemon mit großer Speicherauslastung behandeln?

Immer wenn eine neue Verbindung über Sockets angenommen wird, verzweige ich einen neuen Prozess, um die Verarbeitung für jede empfangene Verbindung zu kümmern. Da der Parent-Prozess sehr groß ist, versucht der Prozessor bei jedem Fork-Vorgang, Speicher für ein neues Kind zu reservieren, aber aufgrund des begrenzten Speichers benötigt es viel Zeit, um ein neues Kind hervorzubringen, wodurch die Antwortzeit erhöht wird. Oft hängt es sogar für eine einzelne Verbindung herunter.

Übergeordneter Prozess erstellt 9 große Hashwerte. Für jedes Kind muss ich im schreibgeschützten Modus auf einen oder mehrere Hashes verweisen. Ich werde Hashes nicht durch Child aktualisieren. Ich möchte etwas wie copy-on-write verwenden, mit dem ich ganze 100mb oder ganze globale Variablen teilen kann, die von Eltern mit allen Kindern erstellt wurden. oder irgendein anderer Mechanismus wie Threads. Ich erwarte, dass der Server eine Anforderung von mindestens 100 pro Sekunde bekommt und es in der Lage sein sollte, alle von ihnen parallel zu verarbeiten. Im Durchschnitt wird ein Kind in 2 Sekunden beendet.

Ich verwende Cygwin unter Windows XP mit nur 1 GB RAM. Ich finde keinen Weg, dieses Problem zu lösen. Kannst du etwas vorschlagen? Wie kann ich Variablen teilen und auch 100 untergeordnete Prozesse pro Sekunde erstellen und sie verwalten und synchronisieren,

Vielen Dank.

Antwort

3

Anstelle von Gabelung gibt es zwei andere Ansätze, um gleichzeitige Verbindungen zu behandeln. Entweder verwenden Sie Threads oder einen Polling-Ansatz.

Im Thread-Ansatz für jede Verbindung wird ein neuer Thread erstellt, der die E/A eines Sockets behandelt. Ein Thread wird im selben virtuellen Speicher des Erstellungsprozesses ausgeführt und kann auf alle Daten zugreifen. Stellen Sie sicher, dass Sperren zum Synchronisieren des Schreibzugriffs auf Ihre Daten verwendet werden.

Ein noch effizienterer Ansatz ist die Verwendung von polling über select(). In diesem Fall behandelt ein einzelner Prozess/Thread alle Sockets. Dies funktioniert unter der Annahme, dass die meiste Arbeit I/O sein wird und dass die Zeit, die damit verbracht wird, auf I/O-Anforderungen zu warten, damit verbracht wird, mit anderen Sockets umzugehen.

Gehen Sie bei diesen beiden Optionen weiter und entscheiden Sie, welche für Sie am besten geeignet ist.

Siehe zum Beispiel: http://www.perlfect.com/articles/select.shtml

2

Wenn Sie, dass viele Daten haben, frage ich mich, warum Sie nicht einfach eine Datenbank verwenden?

2

Diese Architektur ist für Cygwin ungeeignet. Sich auf echte Unix-Systeme zu stürzen ist billig, aber auf gefälschten Unix-Systemen wie Cygwin ist es furchtbar teuer, weil alle Daten kopiert werden müssen (echte Units verwenden Copy-on-Write). Die Verwendung von Threads ändert das Speichernutzungsmuster (höhere Basennutzung, aber kleinere Erhöhung pro Thread), aber die Chancen stehen noch immer ineffizient.

Ich würde Ihnen raten, einen Single-Process-Ansatz mit Polling und möglicherweise auch nicht-blockierende IO zu verwenden.

+0

Ist die emulierte Windows-Version von Perl nicht ein Thread im selben Prozess? Das hat mich in letzter Zeit gebissen und daran erinnere ich mich. –

+0

Ja, sie sind beide als Win32-Threads implementiert, aber ein gefälschter Prozess wird nicht auf die gleiche Weise implementiert wie ein iThread aus einer Perl-Perspektive. –