
Als CGI-Sprache eingesetzt, hat Perl einen gravierenden Nachteil: Für jeden Request (und das können bei einem populären Web-Server Dutzende pro Sekunde sein) muß der Interpreter das entsprechende Script analysieren, auf Syntax-Fehler überprüfen, in den internen Bytecode übersetzen und schließlich ausführen. Bindet es noch zusätzliche Perl-Module ein, läuft aber relativ kurz, kann das Verhältnis von Lade- zu Ausführungszeit schon mal mehr als 10 : 1 betragen. Für wirklich zeitkritische Anwendungen blieb bislang nur eine Umsetzung des Scripts in C, da übersetzte Programme fast verzögerungsfrei anlaufen.
Mit dem Web-Server `Apache' und der mod_perl-Distribution von Doug MacEachern ist dies jedoch nicht mehr notwendig: Das mod_perl-`Plug-in' versorgt den Web-Server mit der Perl-Runtime-Library. So ausgestattet, behält er einmal ausgeführte Scripts startfähig im Speicher und durchläuft den Lese-Check-Compile-Prozeß nur, wenn sich der Inhalt des Scripts geändert hat. Das reduziert die mittlere Ausführungszeit für einen HTTP-Request dramatisch, Performance-Verbesserungen um das Zehn- bis Zwanzigfache sind keine Seltenheit. Damit der Server diese Aufgabe übernimmt, ist die Apache zusammen mit der mod_perl-Distribution zu übersetzen und zu installieren (siehe Kasten `Installation').
Apache::Registry heißt das Modul, das Perl-CGI-Scripts so performant ausführt. Es wird aktiv, falls ein HTTP-Request auf Scripts in bestimmten Verzeichnissen vorliegt, packt das gesamte Script in eine Perl-Subroutine und führt diese aus. Hieraus ergeben sich einige Unterschiede zum normalen CGI-Betrieb. So sollte jedes Script mit der Sequenz
use CGI::Switch; $query = CGI::Switch->new(); print $query->header();
beginnen, bevor es irgendwelche Ausgaben nach stdout schickt.
Scripts, die Lincoln Steins CGI.pm benutzen, laufen fast unverändert mit dem Apache-Plug-in, wenn man statt des Package CGI den dynamischen Schalter CGI::Switch verwendet, der entsprechend den Anforderungen zwischen regulärem CGI und Apache::CGI unterscheidet. Das Listing reg.pl zeigt als Anwendung ein Registrierungsskript, das in ein Formular eingetragene EMail-Adressen zeilenweise in einer Datei speichert.
Das in Zeile 7 erzeugte CGI::Switch-Objekt bietet eine komfortable Schnittstelle zu eingehenden Formular-Parametern und vereinfacht später die Ausgabe einiger HTML-Tags. Liegt als Eingabeparameter keine EMail-Adresse vor, verzweigt Zeile 9 zur Subroutine print_form, die ein Formular zur Eingabe einer EMail-Adresse ausgibt.
Adressen, die der reguläre Ausdruck in Zeile 13 plausibel findet, hängt reg.pl an die Datei email.dat an, falls sie sie noch nicht enthält (Zeilen 18 bis 31). Wegen der in der CGI-Welt üblichen parallelen Ausführung von Requests muß sich das Script dafür zunächst mit flock() den exklusiven Zugriff auf email.dat sichern. Paßt die eingetrage EMail-Adresse nicht in das einfache Raster `_@_._', gibt reg.pl eine Fehlermeldung aus.
Die Subroutine print_form() verarbeitet als zweiten Parameter eine Meldung, die sie zusammen mit dem Registrierungsformular in HTML ausgibt. Das Eingabefeld behält eventuell bereits gesetzte Werte bei. Das aus dem Hauptprogramm hereingereichte CGI::Switch-Objekt $q bietet die Methoden aus CGI.pm und erlaubt eine optisch ansprechende Formulierung des HTML-Textes. Gegenüber normalem CGI-Betrieb ergibt sich bei reg.pl durch die im Server eingebaute Perl-Bibliothek eine Performance-Verbesserung um den Faktor 10.
Allerdings birgt der Ansatz, lauffähige Scripts im Speicher zu halten, auch Tücken: So behalten etwa globale Variablen ihren Wert über die Laufzeit des Scripts hinaus bei. Zusätzlich verzweigt der Apache HTTP-Requests alternierend an seine Child-Prozesse - und die Werte globaler Variablen bleiben in deren Adreßraum konstant. Das Script
use CGI::Switch; my $cgi = CGI::Switch->new(); print $cgi->header(); print "globalvar=", $globalvar++, "(PID=$$)\n";
liefert pro Aufruf den Wert einer globalen Variablen $globalvar> samt der ID des ausführenden Prozesses zurück ($$). Mehrfach vom Apache-Plug-in ausgeführt, erzeugt das Script nacheinander folgende Ausgaben:
globalvar=0 (PID=29045) globalvar=0 (PID=29046) globalvar=0 (PID=29049) globalvar=0 (PID=29054) globalvar=1 (PID=29045) globalvar=1 (PID=29046) globalvar=1 (PID=29049) globalvar=2 (PID=29045) globalvar=2 (PID=29046)
Lösung des Rätsels: Erwischt ein HTTP-Request zufällig wieder denselben Child-Prozeß, erhöht sich der Wert der globalen Variablen $globalvar gegenüber dem letzten Aufruf um 1. Man sollte also auf globale Variablen ganz verzichten.
mod_perl bietet übrigens nicht nur eine Performance-Steigerung bei der Ausführung von CGI-Scripts, sondern eine universelle Schnittstelle zum Apache: Mit simplen Perl-Scripts kann man so Server Side Includes steuern, die User-Authentisierung erweitern oder einen intelligenten Proxy-Server bauen.
MICHAEL SCHILLI
ist Softwareentwickler bei Black Sun Interactive, San Francisco.
Dieser Text ist der Zeitschriften-Ausgabe 07/1997 von iX entnommen.
Parallelprogrammierung - die Kunst der Multi-Core-Nutzung
Agile ALM - agile Praktiken im Application Lifecycle Management
Webentwicklung - Applikationen für mobile Clients
HTML5, CSS3, WebGL: Das iX-Sonderheft zum Thema Webdesign fasst die wichtigsten Neuerungen der aktuellen und kommenden Webstandards zusammen.