9. Warum der Aufwand?

Offenbar sind C-Programme wortreicher als Python-Programme – in nichttrivialen Beispielen wird das deutlicher werden. Tatsächlich hat C noch erheblichere Nachteile gegenüber Python, insbesondere den, dass es sehr einfach ist, in C schlimme Fehler zu machen – die meisten Einbrüche in Rechnersysteme nutzen klassische C-Fehler aus.

Warum dann in C programmieren? Der offensichtlichste Grund: Geschwindigkeit. Das Programm

#include <stdio.h>

int main(void)
{
  int i, k;
  double res=0;

  for (i=1; i<10000; i++) {
    for (k=1; k<10000; k++) {
      res += i/(double)k;
    }
  }
  printf("%f\n", res);
  return 0;
}

braucht auf meinem Rechner 1.46 Sekunden.

Das äquivalente Python-Programm

res = 0.
for i in range(1, 10000):
  for k in range(1, 10000):
    res += i/float(k)
print res

läuft hingegen rund 160 Sekunden, über 100 Mal länger. Natürlich würde das so niemand schreiben. In der Tat verbringt Python lange Zeit mit dem Bauen um Abreißen der Listen von range, und schon der Übergang zu xrange bringt einen Geschwindigkeitsgewinn von etwa 30%. Der Übergang zu

  seq = range(1, 10000)
  multipliers = [1/float(k) for k in seq]
  res = 0.
  for i in seq:
    res += sum(
      itertools.starmap(operator.mul,
        itertools.izip(itertools.repeat(i), multipliers)))
  print res

– bei dem man sozusagen die Umwandlung in floats samt Division nur einmal am Anfang durchführt – reduziert die Ausführungsdauer auf rund 40 Sekunden. Das ist immer noch ein ganzes Stück von C weg, aber immerhin acht Mal schneller als die Originalversion (dieses Verhältnis würde noch wachsen, wenn man die Sequenzen länger machen würde). C überholen kann man allerdings nur mit Hirnschmalz. Man kann nämlich beobachten, dass wir letztlich ∑ iki∕k ausrechnen und dass hier die Summationsreihenfolge vertauscht werden kann, ∑ k=1n-11∕ki=1n-1i. Die innere Summe kann man direkt auswerten und kommt auf n(n- 1)2. Das resultierende Programm,

  res = 0
  n = 10000
  iSum = n*(n-1)/2.
  for k in range(1, n):
    res += iSum/k
  print res

läuft in 0.023 Sekunden, also 50 Mal schneller als das C-Programm. Das ist durchaus typisch: Gute Algorithmen und eine saubere Problemanalyse bringen häufig genug mehr als trickreiche Optimierungen oder Implementationen in “schnellen” Sprachen.

In der Regel liegt der Geschwindigkeitsunterschied von C zu Python für typische computerlinguistische Probleme bei etwa einem Faktor 10 oder 20 – wenn C und Python identische Algorithmen verwenden.

Gerade bei interaktiven Programmen ist auch das häufig nicht wichtig, da der Rechner ohnehin die meiste Zeit mit Warten auf den Benutzer verbringt. In anderen Fällen ist es egal, ob das Programm 0.02 oder eine Sekunde läuft, der Unterschied zwischen zwei Stunden oder zwei Tagen Entwicklungszeit ist aber durchaus relevant.

Dennoch: Gerade bei rechenintensiven Problemen lohnt der Übergang zu C oder einer anderen “mid-level”-Sprache.

Das gilt noch mehr, wenn man an der Hardware oder an einzelnen Bits herumfummelt.


Markus Demleitner

Copyright Notice