DS2のthreadでマルチスレッド処理を実行する際に内部にsetを含む場合と含まない場合の話

termメソッドの使い方で思うところがあったので、それを説明しようと考える

テストデータ作ろう

そういや今までデータセットはDS2の外で普通に作ってたな。せっかくだからDS2で作ろうか

テストデータ大量に作って、パフォーマンス測定したい人もいそうだからどうせなら
スレッド(thread)で作るか

そういや前スレッドの説明したときはsetステートメントを含むスレッドだったな~。
含まない時と挙動違うんだよな。
参考記事:http://sas-tumesas.blogspot.jp/2016/03/ds2thread.html


ということで今回はsetを含まないスレッドの話になりました。


スレッド内にsetがあった場合、SASがその参照先を適当に分けて、平行で処理して、後で縦にガッチャンコされます。
(ちなみに分割→処理→縦結合なので、スレッド内の処理書く時に、全体を通して値を縦に引き継いだりするretain系の処理いれてると分断されて、思ったとおりにならないから気をつけて)

前回はスレッド作成と呼び出しを分けましたが、今回は1つのDS2プロシジャステップ内にいれてます(どっちでもいいです)
さて、以下のコードを実行した場合、Q1は何オブザベーションになるでしょうか?

proc ds2  libs=work;
/*スレッド定義*/
thread mkdata/overwrite=yes;
declare double i x;
method init();
streaminit(777);
do i = 1 to 5;
x=rand('uniform');
output;
end;
end;
endthread;
run;
/*スレッド使用*/
data Q1(overwrite=yes);
dcl thread mkdata mkdata;
method run();
set from mkdata threads=3;
end;
enddata;
run;
quit;























正解は15obsでした。
1スレッド5obs×3スレッドでした。へ~。
わざとiをdropしてないので何が起きてるかわかりやすいはずです。
あと、横道にそれますが、コールルーチンがDS2にはないので
call streaminit()ではなくstreaminit関数でいいのです。違和感ですね

ただ、位置はここでいいのかな~?スレッド分重複で実行される?まあそれでも問題ないけど。
実行の方で設定する?でもそっちのinitでやってもスコープ?違うくて影響ないみたい。

まあいいや、本筋に戻ります。
当然、1スレッドのオブザベーション数をパラメーターにしたいという要望もあるでしょう。
その場合、スレッド定義にメソッドのときのように括弧でパラメータを設定します。
そして、使用する前にパラメータに値をセットするのはserparamsメソッドというものを使います。


proc ds2  libs=work;
/*スレッド定義*/
thread mkdata(double obs)/overwrite=yes;
declare double i x ;
method init();
streaminit(777);
do i = 1 to obs;
x=rand('uniform');
output;
end;
end;
endthread;
run;
/*スレッド使用*/
data Q2(overwrite=yes);
dcl thread mkdata mkdata;
method init();
mkdata.setParms(10000);
    end;
method run();
set from mkdata threads=3;
run;
quit;


で30000obsできます。

以下はオマケ、以下2つスレッドを作ってますが、スレッドの中に合計ステートメントを入れるか外に入れるかでどう違ってしまうかを確認できます。

proc ds2  libs=work;
/*スレッド定義1*/
thread omake1/overwrite=yes;
declare double sum ;
method run();
set Q2;
sum + x;
end;
endthread;
run;
/*スレッド定義2*/
thread omake2/overwrite=yes;
method run();
set Q2;
end;
endthread;
run;

/*スレッド使用1*/
data A1(overwrite=yes);
dcl thread omake1 omake1;
method run();
set from omake1 threads=3;
end;
enddata;
run;

/*スレッド使用2*/
data A2(overwrite=yes);
dcl thread omake2 omake2;
dcl double sum;
method run();
set from omake2 threads=3;
sum+x;
end;
enddata;
run;

quit;

ちなみにA2の最終obsのsumは

proc means data=Q2 sum;
var x;
run;

と一致します。


じゃあ、なんだかこれを見てるとスレッドを利用してグループ集計処理とかもできないのって?感じですが、
どうもそうでもないようで、いずれ紹介しますが、byでlast.出力で、byの途中の中途半端なところでスレッドが切れないようにやってくれるみたいですが、まだ検証中なので乞うご期待です。
(その認識であってますか?知ってたら情報ください)

0 件のコメント:

コメントを投稿