コンピューティングの進歩に伴い、ワークステーションのスレッドは 1 コアから 2 コア、4 コアになり、64 スレッドになりました。 一方、.jsl は事実上シングルスレッドのままです。 一部のプラットフォームではすべてのスレッドが使用されることはわかっていますが、単純な JSL 操作を複数のスレッドに自由に実行できるようにしたいと考えています。 たとえば、10,000,000 行のデータを行単位で処理するスクリプトがある場合、for ループで行ごとに反復処理を行っており、各行の結果が他の行から独立していることがわかっている場合、それを分割したいと思います。 64 個の非同期 for ループへの操作を実行し、64 個のループが並行して完了するまで他の実行を一時停止し、すべてが完了したら単一スレッドの同期スクリプトに戻ります。これは、.py で Pool() と poolObject.join を使用するのと同じです。
こんにちは、スティーブさん
JMP には、複数のコアを活用しようとする箇所がたくさんあります。圧縮データ テーブルの保存/オープン (各列は別のスレッドに送信されます) から、複数の列を持つ分散プラットフォーム (各分散分析は別のスレッド)、へMersenne-Twister ランダム均一ジェネレーター。 ご覧のとおり、マルチスレッドはさまざまな場所で実行されます。
それで、実際にはそのようなリストはありません。 ここでの疑問の動機は何でしょうか?
やあ、ジェフ、
マルチスレッドを利用しているプラットフォーム/組み込みタスクはどこで見つけられますか?
すぐ上で述べたように、これは JSL で行うことの範囲を超えたものです。 マルチスレッドの恩恵を受けると思われる特定の操作がある場合は、詳細を含む他のウィッシュを開いてください。
この願いには多くの投票がありますが、残念ながら、Parallel Assign() で提供されるもの以上のものを実現することは困難です。 ユーザー インターフェイスとの緊密な統合と JMP の対話的な性質のため、可能な JSL を基本的に Parallel Assign で許可されるものに制限せずにスレッドセーフな環境を提供することはできません。
マルチスレッドを活用する最善の方法は、組み込みのプラットフォームを可能な限り使用することです。 これらのプラットフォームでは、マルチスレッド ソリューションを直接提供できます。マルチスレッド化が役立つと思われる組み込み操作の他のウィッシュを開いて、マルチスレッド化をさらに希望する場所を知らせる最良の方法です。
単純な JSL 操作を複数のスレッドに分配する限り、そのための Parallel Assign() と呼ばれる関数があります。これは作業をチャンクに分割し、各チャンクのコードの結果が 1 つの数値になり、操作全体の結果は次のようになります。数値の行列。
Parallel Assign() のスクリプト インデックスにはおもちゃの例があり、Frame Size() の 2 番目の例は、マンデルブロ集合データを計算するためのより複雑な例を示しています。 別の小さな例は次のとおりです。 @Craige_Halesさんのループに関する JSL クックブックの投稿そしてそこにありますマンデルボットについてさらに詳しく彼のブログで。
マルチスレッドを使用してファイルのリストから最大のファイルを検索する別の例を以下に示します。 このスクリプトは最初にシングルスレッド バージョンを実行します。このタスク マネージャーのスクリーンショットでは、アクティビティの両方の部分が確認できます。 シングルスレッドバージョンはロングメサ、パラレルバージョンはトールピークです。 8 コア上の 17,000 ファイルの場合、時間は 13 秒から 4.5 秒、つまり 3 倍速くなりました。 理想的ではありませんが、よくあることですが、スレッドはいくつかのリソース (この場合はディスク アクセスなど) を共有しています。
並列実行される JSL は、共有されたグローバル状態を変更しないように単純である必要があります。 そのため、最初のステップとして一部のグローバルがコピーされます。 これは、並列コードがデータ テーブルの作成やディスプレイとの対話などの操作を実行できないことも意味します。
私たちは、より充実したインターフェイスが必要となる他の単純なアクションにはどのようなものがあるのかを知ることに興味があります。 私が知っているのは、各労働者がその番号以外のアイテムを返却するというものです。 基本的に、これは結果に行列の代わりにリストを使用することを意味します。
----
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