Con l'avanzare dell'informatica, sono passato da 1 core a 2 core a 4 core... a 64 thread sulla mia workstation. Nel frattempo .jsl è rimasto effettivamente a thread singolo. So che alcune piattaforme utilizzeranno tutti i thread, ma mi piacerebbe essere in grado di eseguire semplici operazioni jsl a piacimento su più thread. Ad esempio, se ho uno script che opera per riga su 10.000.000 di righe di dati, se eseguo l'iterazione per riga in un ciclo for e so che il risultato di ogni riga è indipendente dalle altre righe, vorrei dividerlo operazione in 64 cicli for asincroni, sospendere altre esecuzioni mentre i 64 cicli vengono completati in parallelo, quindi tornare a un singolo script sincrono a thread dopo che tutto è completo, proprio come farei in .py con Pool() e poolObject.join.
Ciao Jeff,
Dove posso trovare quali piattaforme/attività integrate sfruttano il multi-threading?
Come notato direttamente sopra, questo desiderio va oltre lo scopo di ciò che faremo in JSL. Se ci sono operazioni specifiche che ritieni possano trarre vantaggio dal multithreading, apri altri desideri con i dettagli.
Sebbene questo desiderio abbia molti voti, sfortunatamente qualsiasi cosa in più rispetto a ciò che viene offerto da Parallel Assign() sarà difficile da realizzare. A causa della stretta integrazione con l'interfaccia utente e della natura interattiva di JMP, non è possibile fornire un ambiente thread-safe senza limitare il possibile JSL essenzialmente a ciò che consente Parallel Assign.
Il modo migliore per sfruttare il multithreading è utilizzare il più possibile le piattaforme integrate. Queste piattaforme sono dove possiamo fornire direttamente soluzioni multithread.Aprire altri desideri per operazioni integrate in cui ritieni che il multithreading possa essere utile è il modo migliore per farci sapere dove vorresti vedere più multithreading.
Per quanto riguarda la produzione di semplici operazioni JSL su più thread, esiste una funzione chiamata Parallel Assign() per questo. Suddivide il lavoro in blocchi in cui il codice per ogni blocco risulta in un singolo numero e il risultato dell'intera operazione è una matrice di numeri
C'è un esempio di giocattolo nell'indice di scripting per Parallel Assign(), e il secondo esempio per Frame Size() mostra un esempio più elaborato per calcolare i dati dei set di Mandelbrot. Un altro piccolo esempio è in @Craige_Hales 'S Post del libro di cucina JSL sui loop e c'è di più su Mandelbot nel suo blog.
Di seguito ho incluso un altro esempio che trova il file più grande in un elenco di file utilizzando il multi-threading. Lo script esegue prima una versione a thread singolo e puoi vedere entrambi gli scatti di attività in questa schermata del task manager. La versione single-thread è la mesa lunga e la versione parallela è il picco alto. Per 17.000 file su 8 core, il tempo è passato da 13 secondi a 4,5 secondi, ovvero 3 volte più veloce. Non è l'ideale, ma come spesso accade, i thread condividono alcune risorse, come l'accesso al disco in questo caso.
Il JSL che viene eseguito in parallelo deve essere semplice in modo da non modificare lo stato globale condiviso. Ecco perché alcuni globali vengono copiati come primo passaggio. Significa anche che il codice parallelo non può eseguire operazioni come creare tabelle di dati o interagire con il display.
Siamo interessati a sapere che tipo di altre semplici azioni in cui potremmo aver bisogno di un'interfaccia più ricca. Uno che conosco è che ogni lavoratore restituisca articoli diversi da quel numero. In sostanza, ciò significherebbe utilizzare un elenco per i risultati anziché una matrice.
----
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