2017-07-11 8 views
1

例コード:はのparforループ内でクラスメソッドを参照:クラスの大幅なメモリ使用量

classdef testcls 
    methods 
     function sayhello(~) 
      disp('Hello! ') 
     end 
    end 
end 

と私は

A = testcls; 
parfor ii = 1:4 
    A.sayhello() 
end 
以下のよう parforでメソッドを呼び出す場合、今Mlintは私のパフォーマンスを告げますループ内の Aの使用に関する問題:

The entire array or structure 'obj' is a broadcast variable. This might result in unnecessary communication overhead.

そして私はsuppr匿名関数を使用してこのメ​​ッセージを送信してください:

A = testcls; 
f = @A.sayhello; 
parfor ii = 1:4 
    f() 
end 

私の質問は、とにかくこの速度を助けますか? parforでメソッドを呼び出す方法はありますか?

次に、関数の入出力引数を設定したい場合は、もっと複雑になるでしょうか?

classdef testcls 
    methods 
     function [out1,out2] = sayhello(~,n) 
      out1 = (['Hello! ', num2str(n)]); 
      out2 = n; 
     end 
    end 
end 

A = testcls; 
f = @A.sayhello; 
[a,b] = deal(cell(4,1)); 
parfor ii = 1:4 
    [a{ii},b{ii}] = feval(f,ii); 
end 

EDIT:

私はメモリのコピー操作に関連する重要なリソース消費を観察しました。基本的に、ジョブ・ディスパッチャーは、すべての変更されたプロパティーを含む各ワーカー用に同一のオブジェクトを作成します。

f = @A.sayhello;このメソッドを使用すると、メソッド自体がクラスプロパティを呼び出したり保存したりしなくても、Matlabはオブジェクト全体を個々のワーカーにmemcpyする必要がなくなります。

私はこれが透明性を確保する方法だと思います。しかし、データ量が膨大な場合、これは頭の中で大きな痛みになるでしょう。

目的の機能をスタンドアロンのファイルベースの機能に分離する代わりに、オブジェクト全体にmemcopyを呼び出さないオブジェクトにsayhelloをパッケージ化する方法がありますか?


編集:示唆的な回答のために@gnoviceに感謝します。私は、parforを静的メソッドと比較するためのテストケースを作成しました。parforは非静的メソッドであり、シリアル実行はarrayfunを使用しています。

テストケース1:非静的メソッド(コントロール)

parfor non-static

parforメモリ使用状況レコードに見られるように、単一のオブジェクトtestclsの作成はで示される、〜700メガバイトのRAMを使用ラベル1の後にclearというラベルのコマンドが続き、ラベル3の上にparforのループが続きます。 parforによるピーク使用量は単一のオブジェクトの約4倍ですが、プールには4人の作業者がいます。

テストケース2:静的メソッドとparfor

parfor static

試験手順は同様に行われ、標識されています。この証拠から、結論は、メソッドを静的にするだけでは、すべての作業者に対して同じオブジェクトが生成されるのを防ぐことができないことになります。

テストケース3:arrayfun

serial

を使用してシリアル評価arrayfunが非連続シリアルバッチの評価を行うため、ここでarrayfunは、単一のスレッドが必要とするより多くのメモリを使用するための理由はありません。したがって証拠。

例コード:

classdef testcls 
    properties 
     D 
    end 
    methods (Static = false) 
     function [out1,out2] = sayhello(~,n) 
      out1 = (['Hello! ', num2str(n)]); 
      out2 = n; 
     end 
    end 
    methods 
     function obj = testcls(~) 
      obj.D = rand(1e8,1); 
     end 
    end 
end 

テストを実行するには、このスクリプトを使用します。

clear;clc;close all 

A = testcls; 
f = @A.sayhello; 
parfor ii = 1:4 
    feval(f,ii) 
end 

あなたはシリアル検証のためarrayfunparforを置き換えることができます。

+1

あなたの最後のサンプルコードは、エラーを与える:「スライスされた変数fが関数ハンドルを参照してはなりません」 - 代わりに 'feval(f、ii)'を使用しなければなりません([こちらを参照](https://www.mathworks.com/help/distcomp/objects-and-handles-in-parfor-loops.html) – whrrgarbl

+0

@ whrrgarbl whoaあなたが正しいです。自分のコードには何の議論もありませんでしたが、私はそれが1つのコードで動作すると思っていました。最も簡単な方法でコードを編集します。 – Yvon

答えて

1

クラスのプロパティを参照する必要がないメソッドの場合は、おそらくそれをstatic methodsにするのが最善です。ドキュメントから:

Static methods are associated with a class, but not with specific instances of that class. These methods do not require an object of the class as an input argument, unlike ordinary methods which operate on specific objects of the class. You can call static methods without creating an object of the class

彼らはそのクラスのオブジェクトを作成せずに呼び出すことができるので、これはあなたが各ワーカー間でオブジェクト全体の不必要な重複を避けるために役立つはずです。

例方法:

classdef testcls 
    ... 
    methods(Static) 
    function sayhello 
     disp('Hello!'); 
    end 
    end 
    ... 
end 

そして、各ワーカーからそれを呼び出すために:

testcls.sayhello(); 
+0

アイデアありがとう!私は比較テストを実行し、その結果を質問に掲載しました。残念なことに静的メソッドでは、同じオブジェクトの産卵が排除されません。スナップショットを見てください。 – Yvon

+1

@ Yvon: 'f = @ A.sayhello;'を使って静的メソッドを呼び出すことは、依然としてオブジェクト 'A'に結びついているので動作しない可能性があります。静的メソッドをオブジェクトなしで呼び出し、クラス名 'f = @ testcls.sayhello;'を使って静的メソッドを再テストします。私はそれについて別の結果が期待されます。 – gnovice

+0

あなたは正しいです。静的メソッドをクラス名で呼び出すと、同じオブジェクトが望ましく生成されなくなります。これは、 "データ"(大量)と "パラメータ"(実行中のプログラムを制御する少数の数値)を区別することができないため、クラス全体の実行時パラメータにアクセスする機会がなくなります。 – Yvon

関連する問題