Allerdings veröffentlichte derselbe Moore 2003 die Arbeit "No Exponential is Forever: Aber" Forever "kann verzögert werden! ", In dem er zugab, dass das exponentielle Wachstum physikalischer Größen über einen langen Zeitraum unmöglich ist. Nur die Entwicklung der Transistoren und ihrer Herstellungstechnologien ermöglichte es, das Gesetz um mehrere Generationen zu erweitern.
Im Jahr 2007 erklärte Moore, dass das Gesetz aufgrund der atomaren Natur der Materie und der Begrenzung der Lichtgeschwindigkeit offenbar bald nicht mehr gelten werde. Derzeit beträgt die maximale Größe eines Transistors in einem Prozessor 5 Nanometer. Es gibt auch Testproben des 3-Nanometer-Prozessors, aber seine Veröffentlichung wird erst 2021 beginnen. Dies deutet darauf hin, dass die weitere Zunahme der Anzahl von Transistoren auf einem Chip bald aufhören wird (bis ein neues Material entdeckt oder der technologische Prozess radikal aktualisiert wird).
Eine der Lösungen für dieses Problem ist das parallele Rechnen. Dieser Begriff wird als eine Möglichkeit zum Organisieren von Computerberechnungen verstanden, bei der Programme als eine Reihe interagierender Rechenprozesse entwickelt werden, die parallel (gleichzeitig) arbeiten.
Das parallele Rechnen nach der Synchronisationsmethode wird in zwei Typen unterteilt.
In der ersten Variante erfolgt die Interaktion von Prozessen über den gemeinsam genutzten Speicher: Auf jedem Prozessor des Multiprozessorsystems wird ein separater Ausführungsthread gestartet. Alle Threads gehören zu einem Prozess. Threads tauschen Daten über einen gemeinsam genutzten Speicherbereich für einen bestimmten Prozess aus. Die Anzahl der Threads entspricht der Anzahl der Prozessoren. Streams werden entweder mithilfe einer Programmiersprache (z. B. Java, C #, C ++ seit C ++ 11, C seit C11) oder mithilfe von Bibliotheken erstellt. In diesem Fall ist es möglich, Threads explizit (z. B. in C / C ++ mit PThreads), deklarativ (z. B. mithilfe der OpenMP-Bibliothek) oder automatisch mithilfe integrierter Compiler-Tools (z. B. High Performance Fortran) zu erstellen. Die beschriebene Variante der parallelen Programmierung erfordert normalerweise eine Form der Steuerungserfassung (Mutexe, Semaphoren,Monitore), um die Flüsse untereinander zu koordinieren.
In der zweiten Variante erfolgt die Interaktion mittels Nachrichtenübertragung. Ein Single-Thread-Prozess wird auf jedem Prozessor in einem Multiprozessorsystem gestartet und kommuniziert mit anderen Prozessen, die auf anderen Prozessoren ausgeführt werden, über Nachrichten. Prozesse werden explizit durch Aufrufen der entsprechenden Funktion des Betriebssystems erstellt, und Nachrichten werden mithilfe einer speziellen Bibliothek (z. B. der MPI-Protokollimplementierung) oder mithilfe von Sprachtools (z. B. High Performance Fortran, Erlang oder Occam) ausgetauscht.
Zusätzlich zu den beiden oben beschriebenen wird auch eine Hybridoption verwendet: Auf Multiprozessorsystemen mit verteiltem Speicher (DM-MIMD), bei denen jeder Knoten des Systems ein Multiprozessor mit gemeinsamem Speicher (SM-MIMD) ist, kann der folgende Ansatz verwendet werden. Auf jedem Knoten des Systems wird ein Multithread-Prozess gestartet, der Threads zwischen den Prozessoren dieses Knotens verteilt. Der Datenaustausch zwischen Threads auf einem Knoten erfolgt über einen gemeinsam genutzten Speicher, und der Datenaustausch zwischen Knoten erfolgt über eine Nachrichtenübertragung. In diesem Fall wird die Anzahl der Prozesse durch die Anzahl der Knoten und die Anzahl der Threads durch die Anzahl der Prozessoren auf jedem Knoten bestimmt. Das hybride Verfahren der parallelen Programmierung ist komplizierter (es ist erforderlich, das parallele Programm auf spezielle Weise neu zu schreiben), aber es ist am effizientesten bei der Verwendung der Hardwareressourcen jedes Knotens des Multiprozessorsystems.
In diesem Artikel schlage ich vor, einen solchen hybriden Ansatz für die Parallelisierung von Berechnungen in Python anzupassen. Das Hauptmerkmal der Arbeit ist der Einsatz der Docker-Container-Technologie. Das entwickelte Framework verfügt über eine Client-Server-Architektur, die die folgenden Elemente enthält.
Auf der Client-Seite:
- Serializer: Entsprechend dem Namen werden Funktionen und ihre Variablen serialisiert (dh sie können auf einem externen Gerät oder Netzwerk gespeichert und dann auf demselben oder einem anderen Knoten in den Speicher geladen werden). Hervorzuheben ist auch der parallele Dekorator, eine Wrapper-Funktion, mit der Sie den Serializer für Funktionen verschiedener Art verwenden können.
- Klassen für die Konfiguration der Server- / Clusterverbindung
- Zusätzliche Sprachfunktionen zum Markieren von zu parallelisierenden Funktionen.
Serverseite:
- Deserializer - Deserialisiert dementsprechend die empfangenen Daten (siehe oben).
- Executor ist eine Klasse, die deserialisierte Daten (Funktionen und deren Argumente) verarbeitet und die erforderlichen Bibliotheken in der virtuellen Umgebung des Python-Interpreters installiert.
Die allgemeine Architektur des zu entwickelnden Systems ist in der Abbildung dargestellt.
Für die Kommunikation zwischen Client und Server können Sockets oder das Twisted Framework verwendet werden, deren Interaktion über die entwickelte API erfolgt.
Die Implementierung dieses Systems setzt die Verwendung der Docker-Technologie voraus. Auf diese Weise können Sie bequem und schnell mit der Softwarekonfiguration beginnen: Starten Sie einfach den Docker-Swarm-Cluster, stellen Sie das Docker-Image auf dem ausgewählten Server bereit und legen Sie die Anzahl der Replikationen fest.
Weitere wichtige Vorteile der Docker-Technologie sind die Schaffung einer homogenen Computerumgebung durch Virtualisierung eines UNIX-ähnlichen Systems (Ubuntu - leichtes Alpine Linux) sowie das Vorhandensein eines Schwarmmodus, mit dem Sie mehrere Container auf verschiedenen Servern ausführen und die Last schnell ausgleichen können, indem Sie Aufgaben auf kostenlose Container übertragen ...
Das entwickelte Framework kann in verschiedenen Bereichen verwendet werden, in denen große Mengen an Berechnungen in der Python-Sprache durchgeführt werden müssen, einschließlich für maschinelles Lernen und Aufgaben zur Analyse tiefer Daten sowie für einfachere Aufgaben, z. B. zur verteilten Entscheidungsprüfung während der Programmierung von Olympiaden.