Programm-Optimierung

In der Informatik, Programm-Optimierung oder Softwareoptimierung ist der Prozess, ein Softwaresystem zu modifizieren, um etwas Aspekt davon Arbeit effizienter zu machen oder weniger Mittel zu verwenden. Im Allgemeinen kann ein Computerprogramm optimiert werden, so dass es schneller durchführt, oder zum Funktionieren mit weniger Speicherlagerung oder anderen Mitteln fähig ist, oder ziehen Sie weniger Macht.

Allgemein

Obwohl das Wort "Optimierung" dieselbe Wurzel wie "optimal" teilt, ist es für den Prozess der Optimierung selten, ein aufrichtig optimales System zu erzeugen. Das optimierte System wird normalerweise nur in einer Anwendung oder für ein Publikum optimal sein. Man könnte die Zeitdauer reduzieren, die ein Programm nimmt, um eine Aufgabe zum Preis des Lassens davon durchzuführen, mehr Gedächtnis verbrauchen. In einer Anwendung, wo Speicherraum an einer Prämie ist, könnte man einen langsameren Algorithmus absichtlich wählen, um weniger Gedächtnis zu verwenden. Häufig gibt es keine "eine Größe passt das ganze" Design, das gut in allen Fällen arbeitet, so machen Ingenieure Umtausche, um die Attribute vom größten Interesse zu optimieren. Zusätzlich ist die Anstrengung, die erforderlich ist, ein Stück der Software zu machen, völlig optimal — unfähig der weiteren Verbesserung — fast immer mehr, als für die Vorteile angemessen ist, die angehäuft würden; so kann der Prozess der Optimierung gehalten werden, bevor eine völlig optimale Lösung erreicht worden ist. Glücklich ist es häufig der Fall, dass die größten Verbesserungen früh im Prozess kommen.

"Niveaus" der Optimierung

Optimierung kann an mehreren "Niveaus" vorkommen:

  • Designniveau

Am höchsten Niveau kann das Design optimiert werden, um besten Gebrauch der verfügbaren Mittel zu machen. Die Durchführung dieses Designs wird aus einer guten Wahl von effizienten Algorithmen einen Nutzen ziehen, und die Durchführung dieser Algorithmen wird aus dem Schreiben guten Qualitätscodes einen Nutzen ziehen. Die architektonische Planung eines Systems betrifft überwältigend seine Leistung. Die Wahl des Algorithmus betrifft Leistungsfähigkeit mehr als jeder andere Artikel des Designs und, da die Wahl des Algorithmus gewöhnlich das erste Ding ist, das entschieden werden muss, können Argumente gegen die frühe oder "Frühoptimierung" hart sein zu rechtfertigen.

In einigen Fällen, jedoch, verlässt sich Optimierung auf das Verwenden mehr wohl durchdachter Algorithmen, von "speziellen Fällen" und speziellen "Tricks" und dem Durchführen komplizierter Umtausche Gebrauch zu machen. Ein "völlig optimiertes" Programm könnte schwieriger sein umzufassen und kann folglich mehr Schulden enthalten als unoptimierte Versionen.

  • Quellcodeniveau

Das Vermeiden des schlechten Qualitätscodierens kann auch Leistung, durch das Vermeiden offensichtlicher "Verlangsamungen" verbessern. Nachdem das, jedoch, einige Optimierungen möglich ist, vermindert das wirklich Haltbarkeit. Einige, aber nicht alle, Optimierungen können heutzutage durch die Optimierung von Bearbeitern durchgeführt werden.

  • Kompilieren Sie Niveau

Der Gebrauch eines Optimierungsbearbeiters neigt dazu sicherzustellen, dass das rechtskräftige Programm mindestens so viel optimiert wird, wie der Bearbeiter voraussagen kann.

  • Zusammenbau-Niveau

Am Tiefststand, Code mit einer Zusammenbau-Sprache schreibend, die für eine besondere Hardware-Plattform entworfen ist, kann den effizientesten und kompakten Code erzeugen, wenn der Programmierer das volle Repertoire von Maschineninstruktionen ausnutzt. Viele auf eingebetteten Systemen verwendete Betriebssysteme sind im Assemblercode aus diesem Grund traditionell geschrieben worden. Programme (anders als sehr kleine Programme) werden selten von Anfang bis Ende im Zusammenbau wegen der Zeit geschrieben und kosten beteiligt. Die meisten werden unten von einer hohen Sprache bis Zusammenbau kompiliert und reichen optimiert von dort. Wenn Leistungsfähigkeit und Größe weniger wichtige große Teile sind, kann auf einer höheren Programmiersprache geschrieben werden.

Mit moderneren Optimierungsbearbeitern und der größeren Kompliziertheit von neuen Zentraleinheiten ist es schwieriger, Code zu schreiben, der besser optimiert wird, als der Bearbeiter selbst erzeugt, und wenige Projekte diesen "äußersten" Optimierungsschritt aufsuchen müssen.

Jedoch wird ein großer Betrag des Codes geschrieben noch heute mit der Absicht kompiliert, auf dem größten Prozentsatz von möglichen Maschinen zu laufen. Demzufolge nutzen Programmierer und Bearbeiter die effizienteren Instruktionen nicht immer aus, die durch neuere Zentraleinheiten oder Marotten von älteren Modellen zur Verfügung gestellt sind. Zusätzlich könnte Zusammenbau-Code, der für einen besonderen Verarbeiter abgestimmt ist, ohne solche Instruktionen zu verwenden, noch auf einem verschiedenen Verarbeiter suboptimal sein, eine verschiedene Einstimmung des Codes erwartend.

  • Durchlaufzeit

Gerade rechtzeitig können Bearbeiter und Assemblerprogrammierer im Stande sein, Durchlaufzeit-Optimierung durchzuführen, die die Fähigkeit zu statischen Bearbeitern überschreitet, indem sie Rahmen gemäß dem wirklichen Eingang oder den anderen Faktoren dynamisch anpassen.

Plattform abhängige und unabhängige Optimierungen

Codeoptimierung kann auch als von der Plattform abhängige und mit der Plattform unabhängige Techniken weit gehend kategorisiert werden. Während die letzten auf die meisten oder allen Plattformen wirksam sind, verwenden von der Plattform abhängige Techniken spezifische Eigenschaften einer Plattform, oder verlassen sich auf Rahmen abhängig von der einzelnen Plattform oder sogar auf den einzelnen Verarbeiter. Das Schreiben oder das Produzieren verschiedener Versionen desselben Codes für verschiedene Verarbeiter könnten deshalb erforderlich sein. Zum Beispiel, im Fall von der Kompilieren-Niveau-Optimierung, sind mit der Plattform unabhängige Techniken allgemeine Techniken (wie Schleife entfaltend, die Verminderung von Funktionsanrufen, Gedächtnis effiziente Routinen, die Verminderung von Bedingungen, usw.) Dieser Einfluss die meisten Zentraleinheitsarchitekturen auf eine ähnliche Weise. Allgemein dienen diese, um die Gesamtinstruktionspfad-Länge zu reduzieren, die erforderlich ist, das Programm zu vollenden und/oder Gesamtspeichergebrauch während des Prozesses zu reduzieren. Andererseits sind von der Plattform abhängige Techniken mit Instruktionsterminplanung verbunden, Instruktionsniveau-Parallelismus, Datenebene-Parallelismus, Optimierungstechniken des geheimen Lagers (d. h., Rahmen, die sich unter verschiedenen Plattformen unterscheiden) und die optimale Instruktionsterminplanung könnten sogar auf verschiedenen Verarbeitern derselben Architektur verschieden sein.

Verschiedene Algorithmen

Rechenbetonte Aufgaben können auf mehrere verschiedene Weisen mit der unterschiedlichen Leistungsfähigkeit durchgeführt werden. Denken Sie zum Beispiel den folgenden C-Codeschnipsel, dessen Absicht ist, die Summe aller ganzen Zahlen von 1 bis N zu erhalten:

interne Nummer i, Summe = 0;

für (ich = 1; ich

Dieser Code kann (das Annehmen keiner arithmetischen Überschwemmung), mit einer mathematischen Formel umgeschrieben werden, wie:

int Summe = N * (1 + N) / 2;

printf ("Summe: %d\n", Summe);

</Quelle>

Die Optimierung, manchmal durchgeführt automatisch durch einen Optimierungsbearbeiter, soll eine Methode (Algorithmus) auswählen, der mehr rechenbetont effizient ist, während er dieselbe Funktionalität behält. Sieh algorithmische Leistungsfähigkeit für eine Diskussion von einigen dieser Techniken. Jedoch kann eine bedeutende Verbesserung in der Leistung häufig durch das Entfernen fremder Funktionalität erreicht werden.

Optimierung ist nicht immer ein offensichtlicher oder intuitiver Prozess. Im Beispiel oben könnte die "optimierte" Version wirklich langsamer sein als die ursprüngliche Version, wenn N genug klein waren und die besondere Hardware zufällig bei der leistenden Hinzufügung und den sich schlingenden Operationen viel schneller ist als Multiplikation und Abteilung.

Optimierung wird sich allgemein darauf konzentrieren, gerade einen oder zwei Aspekte der Leistung zu verbessern: Ausführungszeit, Speichergebrauch, Speicherplatz, Bandbreite, Macht-Verbrauch oder eine andere Quelle. Das wird gewöhnlich einen Umtausch verlangen — wo ein Faktor auf Kosten anderer optimiert wird. Zum Beispiel verbessert die Erhöhung der Größe des geheimen Lagers Zeitverhalten, sondern auch vergrößert den Speicherverbrauch. Andere allgemeine Umtausche schließen Codeklarheit und Bündigkeit ein.

Es gibt Beispiele, wo sich der Programmierer, der die Optimierung durchführt, dafür entscheiden muss, die Software besser für einige Operationen, aber auf Kosten des Bildens anderer Operationen weniger effizient zu machen. Diese Umtausche können manchmal einer nicht technischen Natur — solcher als sein, als ein Mitbewerber ein Abrisspunkt-Ergebnis veröffentlicht hat, das geschlagen werden muss, um kommerziellen Erfolg zu verbessern, aber vielleicht mit der Last kommt, normalen Gebrauch der Software weniger effizient zu machen. Solche Änderungen werden manchmal scherzend pessimizations genannt.

In einigen Fällen kann ein Schnipsel des Codes so optimiert werden, um verfinstert zu werden. Das kann zu Schwierigkeit führen, den Code aufrechtzuerhalten.

Engpässe

Optimierung kann Entdeckung eines Engpasses, eines kritischen Teils des Codes einschließen, der der primäre Verbraucher der erforderlichen Quelle — manchmal bekannt als ein Krisenherd ist. Häufig wird der Grundsatz von Pareto angewandt. d. h. 20 % des Codes sind für 80 % der Ergebnisse verantwortlich.

In der Informatik kann der Grundsatz von Pareto auf die Quellenoptimierung durch das Bemerken angewandt werden, dass 80 % der Mittel normalerweise durch 20 % der Operationen verwendet werden. In der Softwaretechnik ist es häufig eine bessere Annäherung, dass 90 % der Ausführungszeit eines Computerprogramms ausgegeben werden, 10 % des Codes (bekannt als das 90/10 Gesetz in diesem Zusammenhang) durchführend.

Kompliziertere Algorithmen und Datenstrukturen bringen mit vielen Sachen eine gute Leistung, während einfache Algorithmen für kleine Datenmengen — die Einstellung, Initialisierungszeit passender sind, und unveränderliche Faktoren des komplizierteren Algorithmus den Vorteil überwiegen können.

In einigen Fällen kann das Hinzufügen von mehr Gedächtnis helfen, ein Programm geführt schneller zu machen. Zum Beispiel wird ein durchscheinendes Programm jede Linie und Filter und Produktion diese Linie sofort allgemein lesen. Das verwendet nur genug Gedächtnis für eine Linie, aber Leistung ist normalerweise schwach. Leistung kann durch das Lesen der kompletten Datei außerordentlich verbessert werden, dann das gefilterte Ergebnis schreibend, obwohl das viel mehr Gedächtnis verwendet. Das Verstecken des Ergebnisses ist ähnlich wirksam, obwohl, auch größeren Speichergebrauch verlangend.

Wenn man optimiert

Optimierung kann Lesbarkeit reduzieren und Code hinzufügen, der nur verwendet wird, um die Leistung zu verbessern. Das kann Programme oder Systeme komplizieren, sie härter machend, aufrechtzuerhalten und die Fehler zu beseitigen. Infolgedessen werden Optimierung oder Leistungsoptimierung häufig am Ende der Entwicklungsbühne durchgeführt.

Donald Knuth hat die folgenden zwei Erklärungen auf der Optimierung abgegeben:

: (Er hat auch das Zitat Tony Hoare mehrere Jahre später zugeschrieben, obwohl das ein Fehler gewesen sein könnte, weil Hoare abstreitet, den Ausdruck ins Leben gerufen.)

"Frühoptimierung" ist ein Ausdruck, der verwendet ist, um eine Situation zu beschreiben, wo ein Programmierer Leistungsrücksichten das Design eines Stückes des Codes betreffen lässt. Das kann auf ein Design hinauslaufen, das nicht so sauber ist, wie es gewesen sein könnte oder codiert, der falsch ist, weil der Code durch die Optimierung kompliziert wird und der Programmierer wahnsinnig ist, indem er optimiert.

Wenn

man entscheidet, ob man einen spezifischen Teil des Programms optimiert, sollte das Gesetz von Amdahl immer betrachtet werden: Der Einfluss auf das gesamte Programm hängt sehr viel davon ab, wie viel Zeit wirklich in diesem spezifischen Teil verbracht wird, der davon nicht immer klar ist, auf den Code ohne eine Leistungsanalyse zu schauen.

Eine bessere Annäherung soll deshalb zuerst, Code vom Design entwickeln und dann den resultierenden Code im Profil darstellen/bewerten, um zu sehen, welche Teile optimiert werden sollten. Ein einfaches und elegantes Design ist häufig leichter, in dieser Bühne zu optimieren, und Kopierfräs-kann unerwartete Leistungsprobleme offenbaren, die durch die Frühoptimierung nicht gerichtet worden sein würden.

In der Praxis ist es häufig notwendig, an Leistungsabsichten zu denken, wenn man zuerst Software entwirft, aber der Programmierer erwägt die Absichten des Designs und der Optimierung.

Makros

Die Optimierung während der Codeentwicklung mit Makros übernimmt verschiedene Formen auf verschiedenen Sprachen.

Auf einigen Verfahrenssprachen, wie C und C ++, werden Makros mit dem Scheinersatz durchgeführt. Heutzutage können Reihenfunktionen als ein Typ sichere Alternative in vielen Fällen verwendet werden. In beiden Fällen kann der Inlined-Funktionskörper dann weitere Übersetzungszeit-Optimierungen durch den Bearbeiter einschließlich der unveränderlichen Falte erleben, die etwas Berechnung zur Übersetzungszeit bewegen kann.

Auf vielen funktionellen Programmiersprachen werden Makros mit dem mit der Syntaxanalyse maligen Ersatz von Syntaxanalyse-Syntax-Bäumen der Bäume/Auszugs durchgeführt, die er gefordert wird, macht sie sicherer zu verwenden. Seitdem in vieler Fall-Interpretation wird verwendet, der eine Weise ist sicherzustellen, dass solche Berechnung nur am mit der Syntaxanalyse maligen, und manchmal der einzige Weg durchgeführt wird.

Lispeln hat diesen Stil des Makros hervorgebracht, und solche Makros werden häufig "einem Lispeln ähnliche Makros genannt." Eine ähnliche Wirkung kann durch das Verwenden der Schablone metaprogramming in C ++ erreicht werden.

In beiden Fällen wird Arbeit zur Übersetzungszeit bewegt. Der Unterschied zwischen C Makros auf einer Seite, und einem Lispeln ähnlichen Makros und C ++ Schablone metaprogramming auf der anderen Seite, ist, dass die letzten Werkzeuge erlauben, willkürliche Berechnung in der "Übersetzungszeit-Zeit" durchzuführen, während die Vergrößerung von C Makros keine Berechnung durchführt, und sich auf die optimizer Fähigkeit verlässt, es durchzuführen. Zusätzlich, C Makros unterstützen recursion oder Wiederholung nicht direkt, so sind nicht abgeschlossener Turing.

Als mit jeder Optimierung, jedoch, ist es häufig schwierig vorauszusagen, wo solche Werkzeuge den grössten Teil des Einflusses haben werden, bevor ein Projekt abgeschlossen ist.

Automatisierte und manuelle Optimierung

Siehe auch

Optimierung kann durch Bearbeiter automatisiert oder von Programmierern durchgeführt werden. Gewinne werden gewöhnlich für die lokale Optimierung beschränkt, und für globale Optimierungen größer. Gewöhnlich soll die stärkste Optimierung einen höheren Algorithmus finden.

Die Optimierung eines ganzen Systems wird gewöhnlich von Programmierern übernommen, weil es für automatisierten optimizers zu kompliziert ist. In dieser Situation ändern Programmierer oder Systemverwalter ausführlich Code, so dass das gesamte System besser leistet. Obwohl es bessere Leistungsfähigkeit erzeugen kann, ist es viel teurer als automatisierte Optimierungen.

Verwenden Sie einen profiler (oder Leistung Analysator), um die Abteilungen des Programms zu finden, die die meisten Mittel — der Engpass nehmen. Programmierer glauben manchmal, dass sie eine klare Idee davon haben, wo der Engpass ist, aber Intuition ist oft falsch. Die Optimierung eines unwichtigen Stückes des Codes wird normalerweise wenig tun, um der gesamten Leistung zu helfen.

Wenn der Engpass lokalisiert wird, fängt Optimierung gewöhnlich mit einem Umdenken des im Programm verwendeten Algorithmus an. Meistens kann ein besonderer Algorithmus zu einem besonderen Problem spezifisch geschneidert werden, bessere Leistung nachgebend, als ein allgemeiner Algorithmus. Zum Beispiel wird die Aufgabe, eine riesige Liste von Sachen zu sortieren, gewöhnlich mit einer Schnellsortierungsroutine erledigt, die einer der effizientesten allgemeinen Algorithmen ist. Aber wenn eine Eigenschaft der Sachen abbaufähig ist (zum Beispiel, werden sie bereits in einer besonderen Ordnung eingeordnet), eine verschiedene Methode, kann oder sogar eine einzeln angefertigte Sorte-Routine verwendet werden.

Nachdem der Programmierer vernünftig überzeugt ist, dass der beste Algorithmus ausgewählt wird, kann Codeoptimierung anfangen. Schleifen können entrollt werden (für die niedrigere Schleife oben, obwohl das häufig führen kann, um Geschwindigkeit zu senken, wenn es das geheime Zentraleinheitslager überlädt), können Datentypen so klein wie möglich verwendet werden, Arithmetik der ganzen Zahl kann statt des Schwimmpunkts und so weiter verwendet werden. (Sieh algorithmischen Leistungsfähigkeitsartikel für diese und anderen Techniken.)

Leistungsengpässe können wegen Sprachbeschränkungen aber nicht Algorithmen oder im Programm verwendeter Datenstrukturen sein. Manchmal kann ein kritischer Teil des Programms auf einer verschiedenen Programmiersprache umgeschrieben werden, die direkteren Zugang zur zu Grunde liegenden Maschine gibt. Zum Beispiel ist es für sehr höhere Programmiersprachen wie Pythonschlange üblich, Module in C für die größere Geschwindigkeit schreiben zu lassen. In C bereits geschriebene Programme können Module im Zusammenbau schreiben lassen. In D geschriebene Programme können den Reihenmonteur verwenden.

Das Neuschreiben von Abteilungen "zahlt" in diesen Verhältnissen wegen einer allgemeinen "Faustregel" "aus", die als das 90/10 Gesetz bekannt ist, das feststellt, dass 90 % der Zeit in 10 % des Codes und nur 10 % der Zeit mit den restlichen 90 % des Codes ausgegeben werden. Wenn er intellektuelle Anstrengung in die Optimierung gerade stellt, kann eines kleinen Teils des Programms eine riesige Wirkung auf die gesamte Geschwindigkeit haben — wenn der richtige Teil (E) gelegen werden kann.

Manuelle Optimierung hat manchmal die Nebenwirkung, Lesbarkeit zu untergraben. So sollten Codeoptimierungen (vorzugsweise das Verwenden von Reihenanmerkungen), und ihre Wirkung auf die zukünftige bewertete Entwicklung sorgfältig dokumentiert werden.

Das Programm, das eine automatisierte Optimierung durchführt, wird einen optimizer genannt. Die meisten optimizers werden in Bearbeitern eingebettet und funktionieren während der Kompilation. Optimizers kann häufig den erzeugten Code zu spezifischen Verarbeitern schneidern.

Heute werden automatisierte Optimierungen fast auf die Bearbeiter-Optimierung exklusiv beschränkt. Jedoch, weil Bearbeiter-Optimierungen gewöhnlich auf einen festen Satz von ziemlich allgemeinen Optimierungen beschränkt werden, gibt es beträchtliche Nachfrage nach optimizers, der Beschreibungen des Problems und der sprachspezifischen Optimierungen akzeptieren kann, einem Ingenieur erlaubend, kundenspezifische Optimierungen anzugeben. Werkzeuge, die Beschreibungen von Optimierungen akzeptieren, werden Programm-Transformationssysteme genannt und beginnen, auf echte Softwaresysteme wie C ++ angewandt zu werden.

Einige höhere Programmiersprachen (Eiffel, Esterel) optimieren ihre Programme durch das Verwenden einer Zwischensprache.

Bratrost-Computerwissenschaft oder verteilte Rechenziele, das ganze System durch bewegende Aufgaben von Computern mit dem hohen Gebrauch zu Computern mit der Bereitschaftszeit zu optimieren.

Für die Optimierung genommene Zeit

Manchmal kann die Zeit, die genommen ist, um Optimierung an sich zu übernehmen, ein Problem sein.

Optimierung vorhandenen Codes fügt gewöhnlich neue Eigenschaften, und schlechter nicht hinzu, es könnte neue Programmfehler im vorher arbeitenden Code hinzufügen (wie jede Änderung könnte). Weil manuell optimierter Code manchmal weniger "Lesbarkeit" haben könnte als unoptimierter Code, könnte Optimierung Haltbarkeit davon ebenso zusammenpressen. Optimierung kommt an einem Preis, und es ist wichtig, sicher zu sein, dass die Investition lohnend ist.

Ein automatischer optimizer (oder Optimierungsbearbeiter, ein Programm, das Codeoptimierung durchführt) kann selbst, irgendein optimiert werden müssen, um weiter die Leistungsfähigkeit seiner Zielprogramme zu verbessern, oder seine eigene Operation beschleunigen. Eine Kompilation, die mit der Optimierung durchgeführt ist, "angemacht" nimmt gewöhnlich länger, obwohl das gewöhnlich nur ein Problem ist, wenn Programme ziemlich groß sind.

Insbesondere für gerade rechtzeitig Bearbeiter kompiliert die Leistung der Durchlaufzeit Bestandteil, zusammen mit seinem Zielcode durchführend, ist der Schlüssel zur Besserung gesamter Ausführungsgeschwindigkeit.

Notierungen

  • "Die Ordnung, in der die Operationen in jedem besonderen Fall durchgeführt werden sollen, ist eine sehr interessante und neugierige Frage, auf der unser Raum uns völlig nicht erlaubt hereinzugehen. In fast jeder Berechnung ist eine große Vielfalt von Maßnahmen für die Folge der Prozesse möglich, und verschiedene Rücksichten müssen die Auswahl unter ihnen zu den Zwecken eines Rechnens des Motors beeinflussen. Ein wesentlicher Gegenstand ist, diese Einordnung zu wählen, die dazu neigen soll, auf ein Minimum die Zeit zu reduzieren, die notwendig ist, für die Berechnung zu vollenden." — die Zeichen von Ada Byron auf dem analytischen Motor 1842.
  • "Mehr rechnende Sünden werden im Namen der Leistungsfähigkeit begangen (ohne es notwendigerweise zu erreichen), als aus jedem anderen einzelnen Grund — einschließlich der blinden Absurdität." — W.A. Wulf
  • "Wir sollten über die kleine Wirksamkeit vergessen, ungefähr 97 % der Zeit sagen: Frühoptimierung ist die Wurzel des ganzen Übels. Und doch sollten wir nicht auf unsere Gelegenheiten darin kritische 3 % verzichten. Ein guter Programmierer wird in die Selbstgefälligkeit durch solches Denken nicht beruhigt, er wird klug sein, um sorgfältig auf den kritischen Code zu schauen; aber nur nachdem dieser Code" — Donald Knuth identifiziert worden ist
  • "Engpässe kommen im Überraschen von Plätzen vor, versuchen Sie zur zweiten Annahme so nicht und stellen Sie in einer Geschwindigkeitskerbe, bis Sie bewiesen haben, dass es ist, wo der Engpass ist." — Rauben Hecht Aus
  • "Die Erste Regel der Programm-Optimierung: Tun Sie es nicht. Die Zweite Regel der Programm-Optimierung (für Experten nur!): Tun Sie es noch nicht."Michael A. Jackson

Siehe auch

Links


Kampf von Civitate / Macclesfield die Stadt F.C.
Impressum & Datenschutz