コンピューティングが進歩するにつれて、私のワークステーションは 1 コアから 2 コア、4 コア、そして 64 スレッドになりました。 一方、.jsl は実質的にシングル スレッドのままです。 一部のプラットフォームではすべてのスレッドが使用されることはわかっていますが、単純な jsl 操作を自由に複数のスレッドにファームアウトできるようにしたいと考えています。 たとえば、10,000,000 行のデータに対して行単位で動作するスクリプトがある場合、for ループで行ごとに反復処理を行っていて、各行の結果が他の行とは無関係であることがわかっている場合、それを分割したいと思います。操作を 64 個の非同期 for ループに変換し、64 個のループが並列に完了するまで他の実行を一時停止し、すべてが完了したら単一のスレッド化された同期スクリプトに戻ります。
ジェフさん、
マルチスレッドを利用するプラットフォーム/組み込みタスクはどこで確認できますか?
すぐ上で述べたように、これは私たちがJSLでやろうとしていることの範囲を超えています。 マルチスレッド化のメリットがあると思われる特定の操作がある場合は、詳細を記載したその他の要望を開いてください。
この希望には多くの投票がありますが、残念ながら、Parallel Assign() によって提供されるもの以上のものを実現することは困難です。 ユーザー インターフェイスとの緊密な統合、および JMP のインタラクティブな性質のため、可能な JSL を本質的に Parallel Assign が許可するものに制限せずにスレッド セーフな環境を提供することはできません。
マルチスレッドを利用する最善の方法は、組み込みプラットフォームを可能な限り使用することです。 これらのプラットフォームは、マルチスレッド ソリューションを直接提供できる場所です。マルチスレッドが役立つと思われるビルトイン操作について、その他の要望をお寄せいただくことが、マルチスレッドをさらに増やしてほしい場所をお知らせいただく最善の方法です。
単純な JSL 操作を複数のスレッドにファームアウトする限り、そのための Parallel Assign() という関数があります。これは作業をチャンクに分割し、各チャンクのコードが単一の数値になり、操作全体の結果は次のようになります。数の行列。
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