Au fur et à mesure que l'informatique a progressé, je suis passé de 1 cœur à 2 cœurs puis à 4 cœurs... à 64 threads sur mon poste de travail. Pendant ce temps, .jsl est effectivement resté à thread unique. Je sais que certaines plates-formes utiliseront tous les threads, mais j'aimerais pouvoir confier à volonté des opérations JSL simples à plusieurs threads. Par exemple, si j'ai un script qui fonctionne par ligne sur 10 000 000 de lignes de données, si j'itère par ligne dans une boucle for et que je sais que le résultat de chaque ligne est indépendant des autres lignes, j'aimerais diviser cela opération dans 64 boucles for asynchrones, suspendez les autres exécutions pendant que les 64 boucles se terminent en parallèle, puis revenez à un script synchrone à thread unique une fois que tout est terminé, un peu comme je le ferais dans .py avec Pool() et poolObject.join.
Salut Steve,
Il existe de nombreux endroits dans JMP où nous essayons de tirer parti de plusieurs cœurs : depuis l'enregistrement/l'ouverture d'une table de données compressées (chaque colonne est envoyée à un thread différent), jusqu'à la plateforme de distribution avec plusieurs colonnes (chaque analyse de distribution est activée). un fil différent), au Générateur uniforme aléatoire Mersenne-Twister. Comme vous pouvez le constater, le multithreading s'effectue à de nombreux endroits différents.
Donc, nous n'avons pas vraiment une liste comme celle-là. Qu’est-ce qui motive la question ici ?
Salut Jeff,
Où puis-je trouver quelles plates-formes/tâches intégrées profitent du multithread ?
Comme indiqué directement ci-dessus, ce souhait dépasse la portée de ce que nous allons faire en JSL. S'il y a des opérations spécifiques qui, selon vous, bénéficieraient du multithreading, veuillez ouvrir d'autres souhaits avec les détails.
Bien que ce souhait ait de nombreux votes, malheureusement, il sera difficile de réaliser autre chose que ce qui est proposé par Parallel Assign(). En raison de l'intégration étroite avec l'interface utilisateur et de la nature interactive de JMP, il n'est pas possible de fournir un environnement thread-safe sans limiter le JSL possible essentiellement à ce que permet Parallel Assign.
La meilleure façon de profiter du multithreading est d’utiliser autant que possible les plateformes intégrées. Ces plates-formes sont celles où nous pouvons fournir directement des solutions multithread.Ouvrir d'autres souhaits pour les opérations intégrées pour lesquelles vous pensez que le multithreading serait utile est le meilleur moyen de nous faire savoir où vous aimeriez voir plus de multithreading.
En ce qui concerne l'exploitation d'opérations JSL simples sur plusieurs threads, il existe une fonction appelée Parallel Assign() pour cela. Elle divise le travail en morceaux où le code de chaque morceau donne un nombre unique, et le résultat de l'ensemble de l'opération est une matrice de nombres.
Il existe un exemple de jouet dans l'index de script pour Parallel Assign(), et le deuxième exemple pour Frame Size() montre un exemple plus élaboré de calcul des données de l'ensemble de Mandelbrot. Un autre petit exemple est dans @Craige_Hales c'est Article du livre de recettes JSL sur les boucles et il y a en savoir plus sur Mandelbot sur son blog.
J'ai inclus un autre exemple ci-dessous qui trouve le fichier le plus volumineux dans une liste de fichiers utilisant le multithreading. Le script exécute d'abord une version à thread unique, et vous pouvez voir les deux poussées d'activité dans cette capture d'écran du gestionnaire de tâches. La version à filetage unique est la mesa longue et la version parallèle est la haute crête. Pour 17 000 fichiers sur 8 cœurs, le temps est passé de 13 s à 4,5 s, soit 3 fois plus rapide. Ce n'est pas idéal, mais comme c'est souvent le cas, les threads partagent certaines ressources, comme l'accès au disque dans ce cas.
Le JSL qui s'exécute en parallèle doit être simple pour ne pas modifier l'état global partagé. C'est pourquoi certains globaux sont copiés dans un premier temps. Cela signifie également que le code parallèle ne peut pas faire des choses comme créer des tables de données ou interagir avec l'affichage.
Nous souhaitons savoir quels types d'autres actions simples pourraient nécessiter une interface plus riche. L'une que je connais est que chaque travailleur renvoie des articles autres que des numéros. Essentiellement, cela signifierait utiliser une liste pour les résultats au lieu d'une 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