Mit der Weiterentwicklung der Datenverarbeitung bin ich von 1 Kern auf 2 Kerne und dann auf 4 Kerne … auf 64 Threads auf meiner Workstation umgestiegen. Mittlerweile ist .jsl praktisch Single-Threaded geblieben. Ich weiß, dass einige Plattformen alle Threads nutzen, aber ich würde gerne in der Lage sein, einfache JSL-Vorgänge nach Belieben auf mehrere Threads auszulagern. Wenn ich beispielsweise ein Skript habe, das zeilenweise 10.000.000 Datenzeilen bearbeitet, wenn ich in einer for-Schleife zeilenweise iteriere und weiß, dass das Ergebnis jeder Zeile unabhängig von den anderen Zeilen ist, würde ich das gerne aufteilen Operation in 64 asynchrone for-Schleifen umwandeln, andere Ausführungen anhalten, während die 64 Schleifen parallel abgeschlossen werden, und dann zu einem synchronen Skript mit einem einzelnen Thread zurückkehren, nachdem alle abgeschlossen sind, ähnlich wie ich es in .py mit Pool() und poolObject.join tun würde.
Hallo Steve,
Es gibt viele Stellen in JMP, an denen wir versuchen, die Vorteile mehrerer Kerne zu nutzen: vom Speichern/Öffnen einer komprimierten Datentabelle (jede Spalte wird an einen anderen Thread gesendet) bis zur Verteilungsplattform mit mehreren Spalten (jede Verteilungsanalyse ist aktiviert). ein anderer Thread), zum Mersenne-Twister-Zufallsgenerator. Wie Sie sehen, wird Multithreading an vielen verschiedenen Stellen durchgeführt.
Also, So eine Liste haben wir eigentlich nicht. Was treibt hier die Frage an?
Hallo Jeff,
Wo finde ich, welche Plattformen/integrierten Aufgaben Multithreading nutzen?
Wie bereits oben erwähnt, geht dieser Wunsch über den Rahmen dessen hinaus, was wir in JSL tun werden. Wenn es bestimmte Vorgänge gibt, die Ihrer Meinung nach von Multithreading profitieren würden, öffnen Sie bitte andere Wünsche mit den Details.
Obwohl dieser Wunsch viele Stimmen hat, wird es leider schwierig sein, mehr als das, was Parallel Assign() bietet, zu erfüllen. Aufgrund der engen Integration mit der Benutzeroberfläche und der interaktiven Natur von JMP ist es nicht möglich, eine Thread-sichere Umgebung bereitzustellen, ohne die mögliche JSL im Wesentlichen auf das zu beschränken, was Parallel Assign zulässt.
Der beste Weg, die Vorteile von Multithreading zu nutzen, besteht darin, die integrierten Plattformen so oft wie möglich zu nutzen. Auf diesen Plattformen können wir Multithread-Lösungen direkt anbieten.Wenn Sie andere Wünsche für integrierte Operationen offenlegen, bei denen Sie glauben, dass Multithreading nützlich wäre, können Sie uns am besten mitteilen, wo Sie sich mehr Multithreading wünschen.
Was die Auslagerung einfacher JSL-Operationen an mehrere Threads angeht, gibt es dafür eine Funktion namens Parallel Assign(). Sie unterteilt die Arbeit in Blöcke, wobei der Code für jeden Block eine einzelne Zahl ergibt und das Ergebnis der gesamten Operation ist eine Zahlenmatrix.
Im Skriptindex gibt es ein Spielzeugbeispiel für Parallel Assign(), und das zweite Beispiel für Frame Size() zeigt ein ausführlicheres Beispiel für die Berechnung von Mandelbrot-Mengendaten. Ein weiteres kleines Beispiel finden Sie in @Craige_Hales 'S JSL-Kochbuchbeitrag zu Schleifen und da ist mehr über Mandelbot in seinem Blog.
Ich habe unten ein weiteres Beispiel eingefügt, das mithilfe von Multithreading die größte Datei in einer Dateiliste findet. Das Skript führt zunächst eine Single-Threads-Version aus, und Sie können beide Aktivitätsschübe in diesem Task-Manager-Screenshot sehen. Die Single-Thread-Version ist die lange Mesa und die parallele Version ist die hohe Spitze. Bei 17.000 Dateien auf 8 Kernen stieg die Zeit von 13 Sekunden auf 4,5 Sekunden, also dreimal schneller. Nicht ideal, aber wie so oft teilen sich die Threads einige Ressourcen, wie in diesem Fall den Festplattenzugriff.
Die parallel ausgeführte JSL muss einfach sein, damit sie den gemeinsamen globalen Status nicht verändert. Aus diesem Grund werden im ersten Schritt einige Globals kopiert. Dies bedeutet auch, dass der parallele Code keine Datentabellen erstellen oder mit der Anzeige interagieren kann.
Uns interessiert, für welche anderen einfachen Aktionen wir möglicherweise eine umfangreichere Benutzeroberfläche benötigen. Eine Möglichkeit, die ich kenne, besteht darin, dass jeder Arbeiter andere Gegenstände als die Nummer zurückgibt. Im Wesentlichen würde das bedeuten, eine Liste für die Ergebnisse anstelle einer Matrix zu verwenden.
----
Names Default To Here( 1 );
// Example for Parallel Assign().
// get a list of a lot of files
dir = If(Host is("Mac"), "$SAMPLE_DATA", "$JMP_HOME");
all files = Files In Directory( dir, "recursive" );
naf = N Items( all files );
// convert relative paths to full paths
For( i = 1, i <= naf, i++,
all files[i] = dir || "/" || all files[i]
);
// Function that looks at a range of a given file list and returns
// the index of the largest file.
// Importantly, this function uses no global variables.
largest file = Function( {files, first, last},
{i, i large = -1, bytes large = -1, bytes},
For( i = first, i <= last, i++,
bytes = File Size( files[i] );
If( bytes > bytes large,
bytes large = bytes;
i large = i;
);
);
i large;
);
// Single-threaded approach: see all the files to the function.
t0 = Tick Seconds();
lf = largest file( all files, 1, naf );
t1 = Tick Seconds();
Show( naf, lf, all files[lf], t1 - t0 );
// about 13sec on my machine (17k files on Win)
wait(1); // so we can see a break in a CPU activity monitor
// Multi-threaded approach: break the list up into 8 ranges that
// can be handled by separate threads.
t0 = Tick Seconds();
num chunks = 8; // JMP may create this many threads, or fewer
// initialize to -1, so we can detect failure if desired
results = J( num chunks, 1, -1 );
Parallel Assign(
// copy these globals into the thread's local variables
{tf = Name Expr( largest file ), tfiles = all files, tn = num chunks},
// make this assignment for each chunk:
results[i] = Local( {n = N Items( tfiles )},
tf( tfiles, 1 + Floor( (i - 1) * n / tn ), Floor( i * n / tn ) )
)
);
// We need to call the function once more to see which of the top
// files is the overall largest.
top files = all files[results];
toplf = largest file( top files, 1, num chunks );
lf = results[toplf];
t1 = Tick Seconds();
Show( naf, lf, all files[lf], t1 - t0 );
// about 4.5sec