-

- Index

Efficiente programma's schrijven met Powerbasic

Iedere keer dat een gebruiker een bestand vraagt dat in een uitvoerbaar directory gelegen is (bij Xitami is dat standaard cgi-bin), dan zal het programma uitgevoerd worden. Het is dus best mogelijk dat op een bepaald ogenblik een programma meermalen in het geheugen geladen is en uitgevoerd wordt. Je moet je kode schrijven om het opdracht zo snel mogelijk af te handelen en zo het geheugen en de gebruikte resources vrij te geven. Een aantal tips worden hier gegeven.

Strings
PowerBasic gebruikt zoals ieder basic-variant strings met variabele lengte. Dit is heel gemakkelijk, maar het zorgt voor overhead (extra achtergrond-verwerking). Je kan strings met vaste lengte gebruiken op plaatsen waar strings vaak gewijzigd worden (in loops en dergelijke). De volgende opdracht is zeer ongunstig:

a$ = ""
FOR i = 1 TO einde
    prx$ = ...    'berekening van een deel van de string
    a$ = a$ + prx$
NEXT i
Bij iedere lusiteratie moet er een nieuwe plaats voor a$ gereserveerd worden (omdat a$ groter wordt).

Om dit probleem op te lossen maak je beter gebruik van strings met vaste lengte: je berekent op voorhand hoe lang de string kan worden, en je reserveert de nodige ruimte.
Fixed length strings bestaan er in twee uitvoeringen:

  • DIM A$ AS STRING * 100
    Dit is de standaard versie dat ook al beschikbaar was in oudere basic versies zoals Quickbasic. Het is een string dat met spaties aangevuld wordt als de rest van de gereserveerde ruimte niet gebruikt wordt. Dit kan moeilijk-te-vinden fouten veroorzaken, zoals in volgende code snippet:

       ...
       DIM a$ AS STRING * 100
       ...
       a$ = "data-1"
       ...
       IF a$ = "data-1" THEN ...
       ' Dit gedeelte zal nooit uitgevoerd worden
    
       ' De correcte schrijfwijze is:
       IF RTRIM$(a$) = "data-1" THEN ...
       ...
    

  • DIM A$ AS ASCIIZ * 100
    Dit is de verbeterde versie, dat trouwens vaak gebruikt wordt in API-aanroepen. De string wordt afgesloten met een hexadecimale nul (CHR$(0)). Dat wil wel zeggen dat je CHR$(0) nooit in strings zelf kan gebruiken, maar voor ons is dit geen zwaar probleem, aangezien HTML dit teken niet gebruikt. Ook moet je string 1 byte langer zijn dan de verwachte maximale stringlengte. In ons voorbeeld kan je dus 99 bytes opslaan in vorige string.
    Het programmeren met ASCIIZ strings is niet verschillend van het programmeren met strings met variabele lengte, Powerbasic voert alle nodige stappen uit om de CHR$(0) te verwijderen uit de dataflow.
    Nu dat computers uitgerust zijn met gigabytes aan geheugen is het efficienter een grote string te reserveren, dan te moeten werken met kleinere strings die continu in grootte aangepast moeten worden. Strings met variabele lengte zijn een overblijfsel uit het DOS-tijdperk, waar je maar 640kB aan geheugen kon aanspreken.


    Bestanden
    Als je bestanden gebruikt, moet je ze openen als FOR INPUT ACCESS READ LOCK SHARED en controleren op ERR = 70 (permission denied). Je kan een error 70 hebben als het bestand gelocked is door een ander proces. Dit is de layout dat ik gebruik:
    
       ...
       ...
        i = 1
    lockfile:
        OPEN $path + "index.lck" FOR OUTPUT AS #1
        IF ERRCLEAR THEN
            IF i>5 THEN
                PRINT #htmout, "<font color=red>Geen toegang tot de bestanden.<p>
                PRINT #htmout, "<a href='javascript:history.go(0)'>Probeer opnieuw</a>.</font></body></html>
                CLOSE
                EXIT FUNCTION
            END IF
            SLEEP i * 100
            INCR i
            GOTO lockfile
        END IF
    
    

    Hier werk ik met één enkele lockfile (semaphore) dat ik probeer te openen voor het programma gegevens gaat wegschrijven. Van zodra ik de file kan openen, kan ik in alle bestanden schrijven omdat andere processen niet verder geraken. Dit is een veiligheid om je te verzekeren dat je toegang zal hebben tot alle files en dat je niet eindigd met een gebroken database, dat wil zeggen een deel van de ebstanden dat bijgewerkt is, en de andere niet (een nachtmerrie, dat kan ik je verzekeren, als je achteraf de database opnieuw consistent moet maken).


    Mail versturen
    Het versturen van een mailbericht is één van de typische toepassingen van een webapplikatie. Als een bezoeker iets in een gastboek schrijft, dan krijgt de webmaster een mail met de tekst. Het versturen van mail brengt wel complikaties met zich mee:
  • Het versturen van een mail vertraagd het gehele proces.
    Synchroon een mailbericht sturen vertraagt je programma. Een mail sturen kan gemakkelijk 5 seconden duren; tijdens al die tijd blijft je programma 'hangen' en dit is zeker niet goed.
  • Soms moet je je aanmelden bij de mailserver
    daarvoor moet je pop before smtp of CRAM-MD5 gebruiken. Dit maakt het versturen van mail nodeloos ingewikkeld.
    Als een gebruiker meermalen op de verstuur-knop drukt, dan wordt er ieder keer een mailbericht verstuurd, en sommige providers plaatsen een limiet op het aantal mails dat je per uur kan versturen.
  • Sommige smtp servers gebruiken ongestandardiseerde headers.
    De mailserver geeft bijvoorbeeld 2 regels tekst als antwoord, terwijl je programma één regel verwachtte en dus niet meer in de pas loopt.
  • Wat als de mailserver niet beschikbaar is?.
    Het kan gebeuren dat de mailserver dat je wilt gebruiken niet beschikbaar is. Hoe moet je deze situatie oplossen?
  • Mail versturen in je webprogramma zelf is dus geen goede oplossing omdat je enorm veel bijkomende kode moet opnemen om te voorzien op alle mogelijke situaties. Sommige condities kunnen niet opgelost worden met een ingebouwde mailer. Wat zijn de andere oplossingen?
  • Mail versturen met een asynchrone SHELL.
    Maak je mailbericht op en roep een ander programma aan. Dit tweede programma dat asynchroon moet draaien zal het opgemaakte mailbericht versturen. Het hoofdprogramma kan dan normaal afsluiten, terwijl het mailprogramma het bericht zal proberen te versturen.
  • Gebruik een lokale mailserver.
    Het voordeel daarvan is dat de server altijd beschikbaar is. Een mailserver zal rekening houden met alle mogelijke problemen en eventueel het bericht later versturen als de ontvangende server offline is. Een eigen lokale mailserver kan je dan ook verder gebruiken voor mailings en dergelijke. De configuratie van een mailserver is niet eenvoudig, zeker als je het onderste uit de kan wilt halen.
  • Mail drop funktie van de locale mail server.
    Een mailserver heeft altijd een 'mail drop' directory. Bestanden die je in deze directory plaatst worden automatisch verstuurd (als ze aan de juiste formatering voldoen). Mail drop is sneller dan een smtp sessie voeren met de mailserver, zelfs al is die lokaal.

  • Een eenvoudige timer
    Alle basic dialecten hebben een standaard timer, dat je kan gebruiken om te berekenen hoeveel tijd een process nodig heeft gehad. Dit kan nuttig zijn om na te zien welke optimalisatie de beste resultaten oplevert. DE standaart-timer is echte maar nauwkeurig op een tiende van een seconde. De systeemtimer heeft een nauwkeurigheid van een milliseconde, maar daarvoor zal je de API moeten aanroepen.

    
    DECLARE FUNCTION GetTimer LIB "WINMM.DLL" ALIAS "timeGetTime" () AS DWORD
        ' de timer-funktie zit in de windows DLL genaamd "WINMM.DLL" waar het "timeGetTime" genoemd wordt
        DIM starttime AS DWORD
        starttime = GetTimer
        ...         ' Verwerking komt hier
        ...
        PRINT #1, "Total processing time: "  GetTimer - starttime
    
    


    Nog een paar opmerkingen

    Index

    Individuele landingspage bezoekers: