テラシュールブログ

旧テラシュールウェアブログUnity記事。主にUnityのTipsやAR・VR、ニコニコ動画についてのメモを残します。

【Unity】ECSの並列処理"IJobForEach"におけるスケジューリングの挙動

デカイ記事を書こうとして中々更新まで辿り着かないので、今回はサクっとECSの並列処理におけるスケジューリングの挙動について書いておきます。

 

 

IJobForEach?

 

以前は`IJobProcessCommand`という名前のAPIでしたが`IJobForEach`と分かりやすい名前になりました。

ECSは参照するComponentDataでスケジュールが決まる

ECSのIJobForEachを使用すると、特に面倒くさい事を考えなくとも良い感じにスケジューリングしてくれます。
どういった感じにスケジューリングされるのか見ていきます。

f:id:tsubaki_t1:20181223211917j:plain

結論を言えば、どちらかが同じComponentDataに書き込む可能性がある場合、並列で処理されません。逆を言えば、異なるComponentDataに書き込む場合は並列処理が可能で、ミッチリとスレッドを詰めて処理されます。


異なるComponentDataへアクセスするジョブは並列処理する

まず異なるComponentDataへアクセスするジョブは、並列で処理されます。
下の例ではSampleData1とSampleData2という異なるComponentDataへアクセスしている場合の挙動です。

gist.github.com

実行してみると、2つのジョブが並列で実行されるのが確認出来ます。

f:id:tsubaki_t1:20181023234353j:plain

これは複数のJobHandleを合成した場合も同様です。
例えば下のコードではSampleData1とSampleData2に対しての処理と、SampleData3とSampleData4に対する処理を呼び出します。
結果、全て並列で処理されました。

gist.github.com

f:id:tsubaki_t1:20181024000456j:plain

同じComponentDataへアクセスするジョブは並列処理されない

一方、同じComponentDataへアクセスしている場合。この場合は並列処理されず、片方の終了を必ず待ちます。
下のコードでは2つのシステムがComponentDataへアクセスしているので、並列で処理されることはありません。

gist.github.com

これは片方がReadOnlyだった場合も同様です。

f:id:tsubaki_t1:20181023234637j:plain

またJobHandleをまとめた場合、中にReadWriteが一つでもあれば分割されます。
下のコードではまとめたJobHandleの一つがReadWriteなので、処理が分割されています。

gist.github.com

f:id:tsubaki_t1:20181024000846j:plain

ReadOnlyのComponentData同士は並列でアクセスになる

同じComponentDataにアクセスしている場合でも、ReadOnlyの場合は同時にアクセスが可能です。

gist.github.com

f:id:tsubaki_t1:20181023235251j:plain

RequireComponentTagは並列アクセスになる

RequireComponentTagを使用しても並列アクセスになります。絶対に書き込まない設定なので、当然といえば当然ですが。

gist.github.com

f:id:tsubaki_t1:20181223210753j:plain

分割数はチャンクに依存

どうもIJobForEachの処理分割数はチャンクに依存するようになったみたいです。

要するに、たくさんComponentData(タグは除く)を持っているEntityは積極的に分割されやすく、余り持っていないデータは積極的に統合されます。
(分割数が少なければ少ない程、効率的に処理される)

 

感想

ということで並列処理の動作を見てみました。
ECSで「単一の動作を突き詰める」ようなデモを作ろうとすると、頑張って並列化を推し進めようとします。ただ、そこまで頑張らなくともジョブを発行しまくってたら意外とWorker Threadがジョブで埋まるねという感想

とりあえずJobHandleで依存関係を勝手に作ってくれるのは楽で良いです。