Door Kapitein Haddock: Die Python traagheid resulteert er echter in dat er - vergeleken met andere programmeertalen - veel meer processorcapaciteit nodig is om hetzelfde te bereiken. En dat is (onnodig) slecht voor het milieu.
Je blijft eraan voorbij gaan dat de meeste code in verhouding tot het geheel nauwelijks geraakt wordt. Als je kijkt waar performance-bottlenecks in software zitten dan gaat het vrijwel altijd om een beperkte hoeveelheid code die erg vaak geraakt wordt. Pak die stukjes aan en je wint al vrijwel alles wat er te winnen valt. Al die statements die in verhouding tot het geheel maar af en toe geraakt worden zijn niet waar de grote klappen vallen, ook niet als ze op zich gruwelijk inefficiënt worden uitgevoerd. Als ik met een profiler bezig ben performance-bottlenecks op te sporen zie ik regelmatig dat het verschil in hoe vaak statements worden uitgevoerd onderling een factor honderden tot tienduizenden verschilt. Dat kan nog veel hoger, maar als de factor tientallen miljoenen bedraagt is er met een profiler (die zelf vertraagt) niet meer doorheen te komen, dus dat vermijd ik als het even kan.
Verder doet een proces dat op I/O staat te wachten niets, ook niet als het in Python geschreven is. Bij I/O-bound applicaties, en dat zijn er heel wat, doet de applicatie gek genoeg vaak helemaal niet zo veel. De grote adminstratieve systemen op mainframes waar ik ooit volop aan gewerkt heb zijn meer bezig data heen en weer te schuiven dan dat ze CPU-intensieve bewerkingen op die data uitvoeren.
Die verschillen doen ertoe. Die betekenen dat bij een flink deel van de code de winst die je met sneller uitvoeren zou halen, ook qua energieverbruik, marginaal is.
Nog iets qua energieverbruik: ik heb gezien hoe in een computerzaal in de loop van de jaren de mainframes steeds minder ruimte innamen en steeds meer gangen met racks vol Unix- en vooral Windows-servers verschenen. De geluidsdruk van de ventilatoren tussen die racks was op een gegeven moment voor mij nauwelijks meer te harden. De mainframes, inmiddels per stuk zo compact als een forse koelkast, waren daarentegen fluisterstil en als je je hand voor de luchtuitlaat van de koeling hield voelde het eerder koel dan lauw aan. En toch draaide de bulk van de business logic nog altijd op die mainframes, in die 4GL die ook geen snelle taal was. Alle schijven waren trouwens ondergebracht in centrale raid-systemen, ook de Windows- en Unix-servers hadden geen eigen schijven aan boord. De koeling was puur voor de CPUs en moederborden nodig. Je kan je afvragen wat maakt dat voor een minderheidsaandeel in de dataverwerking waar het feitelijk om gaat kennelijk een fors veelvoud aan CPU-kracht nodig is in vergelijking met die mainframes. Ik heb IT'ers met een Windowsachtergrond meegemaakt die hardnekkig het mainframe als "veel te duur servertje" bleven onderschatten omdat ze er met hun verstand niet bij konden dat met zo weinig CPU-kracht zoveel werk verzet kon worden, inclusief een manager die er door dat ongeloof meer dan een jaar voor nodig had voordat eindelijk het muntje viel hoe groot de systemen waren die qua beheer nota bene onder zijn verantwoordelijkheid vielen.
Ik heb trouwens ooit een bericht gelezen dat een bank, ik dacht in Brazilië, tegen alle trends in zijn hele hebben en houden niet van maar juist naar een mainframe converteerde. Ze hadden namelijk niet alleen naar licentie-, beheer- en ontwikkelkosten gekeken maar ook naar energieverbruik, en dat viel zoveel lager uit dat het voor hun de gunstigste oplossing was.
Bij meerdere pakketten die op die Windows-servers draaiden om een relatief klein deel van de totale business logic te bestieren heb ik soms meegekeken als de beheerders daarvan het datamodel aan het bestuderen waren. Telkens bleek zo'n datamodel enorm te zijn. In termen van aantal entiteittypen meer dan eens groter dan het complete corporate datamodel van de eigen systemen, voor een veel beperktere functionaliteit. Kijkend naar hoe die datamodellen in elkaar zaten was de reden daarvoor evident: een pakketbouwer moet klanten met de meest uiteenlopende wensen bedienen en heeft geen maatwerk-datamodel voor zo'n klant maar een waar ongeveer alles wat klanten aan variatie aandragen in onder te brengen is door met de configuratie te goochelen. Dat kan volgens mij niet anders betekenen dan dat het aantal I/O's dat nodig is om een taak uit te voeren een veelvoud is van dat bij een maatwerk-datamodel. Het ligt voor de hand dat dát wel eens een hoop energie kan vreten.
Als je naar energieverbruik kijkt dan moet je kijken naar waar de energie werkelijk in gaat zitten. Er spelen veel meer factoren mee dan alleen de gebruikte programmeertaal, en die is lang niet altijd de belangrijkste factor. Maar inderdaad, kritische CPU-intensieve algoritmes wil je inderdaad niet in een trage taal implementeren. Alleen zijn dat meestal beperkte stukjes code, en die kunnen worden overgezet naar een andere taal. En als het beperkt is dan kunnen de voordelen van zo'n trage taal, qua ontwikkelsnelheid, leesbaarheid en onderhoudbaarheid (en bij Python zijn die wat mij betreft evident), wel degelijk de balans in het voordeel van zo'n taal uit doen vallen.
En trouwens, voor je een algoritme overzet naar een snellere taal doe je er goed aan om te kijken of het algoritme zelf niet beter kan. Ik heb meer dan eens met een slimmer algoritme verbeteringen bereikt waar de snelheidsverschillen tussen programmeertalen met afstand bij in het niet vallen.
Ik heb, zoals ik schreef, een aantal keer Cython gebruikt bij performance-bottlenecks. Cython is een gecompileerde superset van Python (Python is ook geldige Cython), waarin je naast de dynamische gegevenstypen van Python (duck-typing; de belangrijkste reden waarom het een trage taal is) ook statisch gedeclareerde typen kan gebruiken, zowel Python- als C-typen. Er zit een tool bij om je sourcecode te analyseren die heldere suggesties geeft voor snelheidsverbeteringen. Het resultaat van de compilatie is een module die je rechtstreeks kan importeren in Python-code. Die opzet maakt het isoleren en optimaliseren van problematische brokjes code bijna belachelijk eenvoudig, je hoeft je niet eens te verdiepen in hoe je in C of een andere taal een module die Python kan importeren voor elkaar krijgt, in plaats daarvan tweak je Python-code stapje voor stapje om naar Cython-code met hulp van de aanwijzingen die de tool geeft en zie je de uitvoeringssnelheid met sprongen vooruit gaan. Shared libraries/DLLs zijn trouwens ook vanuit Python te gebruiken, daar kan dus ook het nodige mee.
Een veel gehoord punt van kritiek qua performance is de "global interpreter lock" of GIL die in CPython (de reference implementation) de snelheidswinst van threading grotendeels om zeep helpt. Dat is nooit verholpen omdat a) de Python-runtime dramatisch veel complexer zou worden daarvan; b) single threaded Python bij elke poging daartoe veel trager bleek te worden, wat natuurlijk niet acceptabel is; en c) het probleem te omzeilen is door de verwerking niet over meerdere threads maar meerdere processen te verdelen. Dan ontbreekt de mogelijkheid van werken met gedeelde data-items, én de ellende van race conditions die dat op kan leveren, maar met queue-mechanismes kunnen verwerkingspijplijnen worden opgezet (een basale is ingebouwd in de standard library, voor meer veeleisende situaties vind ik ZeroMQ een aanrader — en niet alleen voor Python). Ik heb bewerkingen op numpy-tabellen (in de beeldverwerkende software die ik noemde) geparallelliseerd door ze memory mapped files als basis te geven (Python en numpy ondersteunen dat), en die kunnen tussen processen gedeeld worden waardoor meerdere processen elk hun "tegeltje" van de afbeelding kunnen verwerken zonder dat immense hoeveelheden data tussen processen heen en weer gepompt hoeven te worden. Dan ben je met volwassen programmeertechnieken bezig, Haddock, en Python is zo volwassen dat die prima ondersteund worden.
Goed, smaken verschillen, maar ik ben (zoals ik zelf aan de lengte van mijn reactie kan zien) meer dan een beetje enthousiast geworden van Python. Dat je argument over uitvoeringssnelheid en energieverbruik mist hoe gelokaliseerd problemen daarmee zijn, hoeveel meer dan alleen de snelheid van de programmeertaal daar een rol in speelt en dat daar oplossingen voor bestaan heb ik denk ik wel genoegzaam onderbouwd.