24.02.2014 Aufrufe

ADMIN Magazin Gestapelt - Schneller und sicherer mit RAID (Vorschau)

Erfolgreiche ePaper selbst erstellen

Machen Sie aus Ihren PDF Publikationen ein blätterbares Flipbook mit unserer einzigartigen Google optimierten e-Paper Software.

Programmieren<br />

Julia<br />

01 $./julia<br />

Am besten baut man den Pfad zur ausführbaren<br />

Datei nun in seine PATH-Variable<br />

ein.<br />

Wie bei vielen interaktiven Tools kann<br />

man jetzt Ausdrücke eingeben wie:<br />

julia> sqrt(2*7)+(6/4)<br />

5.241657386773941<br />

Wie oben schon erwähnt sind sowohl<br />

eine User Manual wie auch Library-Referenz<br />

online abrufbar <strong>und</strong> helfen bei<br />

der Erk<strong>und</strong>ung von Julia. Weil Julia auf<br />

HPC-Umgebungen ausgerichtet ist <strong>und</strong><br />

Parallelverarbeitung dort eine große Rolle<br />

spielt, ist das auch ein integraler Teil von<br />

Julia.<br />

Eintauchen in Julia<br />

Hochspachen, die die Komplexität von<br />

MPI verbergen, erleichtern den Umgang<br />

<strong>mit</strong> Parallelverarbeitung. Das hat jedoch<br />

seinen Preis in Form einer verminderten<br />

Effizienz. Dieser Preis scheint oft gerechtfertigt,<br />

weil der Bequemlichkeitsvorteil<br />

den Effizienznachteil aufwiegt, aber das<br />

MPI hat nach wie vor seine Berechtigung.<br />

Wie im Julia-Manual beschrieben bietet<br />

Julia eine einfaches, einseitiges Messaging-Modell:<br />

„Julias Implementierung des<br />

Message Passing unterscheidet sich von<br />

der anderer Umgebungen wie etwa MPI.<br />

Die Kommunikation in Julia ist generell<br />

einseitig, was heißt, dass Julia nur <strong>mit</strong><br />

einem Prozessor in einer Zwei-Prozessor-Operation<br />

umgehen muss. Darüber<br />

hinaus handelt es sich bei diesen Operationen<br />

typischerweise nicht um Dinge wie<br />

'Nachricht verschicken' <strong>und</strong> 'Nachricht<br />

empfangen', sondern sie ähneln eher<br />

dem Aufruf von Benutzerfunktionen.“<br />

Die Autoren heben außerdem hervor,<br />

dass Julia zwei eingebaute Pri<strong>mit</strong>ive enthält:<br />

„… Remote References <strong>und</strong> Remote<br />

Listing 1: Julia Header beim Startup<br />

02 _<br />

03 _ _ _(_)_ |<br />

04 (_) | (_) (_) |<br />

Calls. Eine Remote Reference ist dabei<br />

ein Objekt, dass von jedem Prozessor<br />

genutzt werden kann, um auf ein Objekt<br />

zu verweisen, dass ein bestimmter<br />

Prozessor speichert. Eine Remote Call ist<br />

eine Anforderung eines Prozessors, eine<br />

Funktion <strong>mit</strong> bestimmten Argumenten<br />

auf einem anderen (oder demselben) Prozessor<br />

auszuführen.“<br />

Dynamisch erweitern<br />

Für die folgenden Beispiele wird Julia<br />

nun auf einer Multicore-Maschine <strong>mit</strong><br />

zwei Prozessoren gestartet:<br />

julia ‐q ‐p2<br />

05 _ _ _| |_ __ _ | A fresh approach to technical computing<br />

06 | | | | | | |/ _` | |<br />

07 | | |_| | | | (_| | | Version 0.0.0+86921303.rc6cb<br />

08 _/ |\__'_|_|_|\__'_| | Com<strong>mit</strong> c6cbcd11c8 (2012‐05‐25 00:27:29)<br />

09 |__/ |<br />

10 julia><br />

Das dynamische Hinzufügen weiterer<br />

Cores wird im nächsten Abschnitt beschrieben,<br />

im Moment sollen nur zwei<br />

Cores benutzt werden. Es ist außerdem<br />

sinnvoll, die Anzahl Cores nicht zu überzeichnen<br />

(das »‐p«-Argument soll also<br />

nicht die Anzahl Cores in der Maschine<br />

übersteigen).Das Beispiel benutzt einen<br />

»remote_call«, um zwei Zahlen auf einem<br />

andren Prozessor zu addieren. Danach<br />

wird das Resultat abgeholt. Man könnte<br />

genauso wieder einen Remote Call benutzen,<br />

um <strong>mit</strong> dem Ergebnis weiterzurechnen.<br />

julia> r = remote_call(2,+,2,2)<br />

RemoteRef(2,1,1)<br />

julia> fetch(r)<br />

4<br />

julia> s = remote_call(2,+,1,r)<br />

RemoteRef(2,1,2)<br />

julia>fetch(s)<br />

5<br />

Remote Calls kehren un<strong>mit</strong>telbar zurück<br />

<strong>und</strong> warten nicht auf die Beendigung des<br />

Task. Der Prozessor, der den Call absetzte,<br />

fährt <strong>mit</strong> seiner nächsten Operation fort,<br />

während der Call irgendwo anders abgearbeitet<br />

wird. ein »fetch()« wartet allerdings<br />

bis das Resultat<br />

verfügbar ist.<br />

Alternativ kann man<br />

auf die Beendigung<br />

eines Remote Calls<br />

warten, indem man<br />

ein »wait()« <strong>mit</strong> der<br />

Remote Reference<br />

absetzt.<br />

Das eben gezeigte<br />

Beispiel ist durch<br />

den Zwang, die Prozessornummern<br />

explizit anzugeben,<br />

nicht besonders portabel. Die meisten<br />

Programmierer benutzen deshalb ein<br />

Julia-Makro namens »spawn«, das diese<br />

Abhängigkeit eliminiert. Zum Beispiel:<br />

julia> r= @spawn 7‐1<br />

RemoteRef(2,1,7)<br />

julia> fetch(r)<br />

6<br />

Auch das Makro »@parallel« ist in Schleifen<br />

sehr nützlich. Weil Julia interaktiv<br />

ist, muss man sich ins Gedächtnis rufen,<br />

dass auf der Kommandozeile eingegebene<br />

Funktionen nicht automatisch entfernten<br />

Cores zur Verfügung stehen (auf<br />

dem lokalen oder einem entfernten Knoten).<br />

Um Funktionen auf allen Cores zu<br />

verwenden muss man »load()« benutzen.<br />

Diese Funktion lädt Julia-Programme automatisch<br />

auf alle Cores, die <strong>mit</strong> einer<br />

Julia-Instanz assoziiert sind. Alternativ<br />

liest Julia das File »startup.jl« im Homedirectory,<br />

wenn es existiert.<br />

Alle Cores aufrufen<br />

Julia kann Cores der lokalen Maschine<br />

oder von entfernten Maschinen (das sind<br />

immer Cluster-Nodes) nutzen. Wie das<br />

geht, wird im Folgenden demonstriert.<br />

Zuerst startet man die Julia-Instanz <strong>mit</strong><br />

einem Core. Die »nprocs()«-Funktion<br />

zeigt die Anzahl verfügbarer Cores der<br />

aktuellen Instanz an:<br />

$ julia ‐q<br />

julia>nprocs()<br />

1<br />

Möchte man nun weitere lokale Cores<br />

hinzufügen, bietet sich die Funktion<br />

»addprocs_local()« an, wie Listing 2<br />

zeigt. In diesem Beispiel wurde ein Core<br />

hinzugefügt <strong>und</strong> nprocs() zeigt daraufhin<br />

zwei Cores an.<br />

julia>nprocs()<br />

2<br />

Remote Cores (solche von anderen<br />

Maschinen) lassen sich auf zweierlei<br />

Weise hinzufügen. Einmal <strong>mit</strong>hilfe der<br />

»addprocs_ssh«-Funktion. Ein Beispiel<br />

zeigt Listing 3, das je einen Core von<br />

den Knoten n0 <strong>und</strong> n2 einbindet. Die<br />

Voraussetzung dafür ist allerdings, dass<br />

Julia auf allen Nodes an derselben Stelle<br />

installiert oder über ein Shared Filesys-<br />

124 Ausgabe 06-2012 Admin www.admin-magazin.de

Hurra! Ihre Datei wurde hochgeladen und ist bereit für die Veröffentlichung.

Erfolgreich gespeichert!

Leider ist etwas schief gelaufen!