3

これが私の問題です(全体像)。大規模で複雑な(つまり、複数レベルのネストされた構造を含む)Matlab構造を使用するプロジェクトがあります。これは予想通り遅いです(特にロード/保存しようとするとき)。これらの構造のいくつかをJavaオブジェクトに変換することにより、ランタイムを改善しようとしています。欠点は、これらのMatlab構造のデータが多くの場所でアクセスされるため、アクセス構文の書き直しが必要なものはすべて禁止されることです。したがって、特にMatlab構造内に格納されている値にアクセスする場合は、JavaオブジェクトがMatlab構造の動作を可能な限り模倣する必要があります(値は1つの場所にのみ設定されるため、設定のためのJavaでの演算子のオーバーロードがありません)考慮すべき要素ではありません)。

私が直面している問題(小さな画像)は、これらの構造の配列からデータにアクセスすることにあります。例えば、

person(1)
  .age = 20
  .name
    .first = 'John'
    .last = 'Smith

person(2)
  .age = 25
  .name
    .first = 'Jane'
    .last = 'Doe'

Matlabを使用すると、次のことが可能になります。

>>age = [person(1:2).age]
age = 
    20    25

Javaで同じことを達成しようとすると、

>>jperson = javaArray('myMatlab.Person', 2);
>>jperson(1) = Person(20, Name('John', 'Smith'));
>>jperson(2) = Person(25, Name('Jane', 'Doe'));
>>age = [jperson(1:2).age]
??? No appropriate method or public field age for class myMatlab.Person[]

Javaオブジェクトにこの動作を模倣させる方法はありますか?私が最初に考えたのは、 Person []クラス を単純に拡張することでしたが、これは最終的なものであるため、可能ではないようです。私の2番目のアプローチは、PersonのArrayListを含むラッパークラスを作成することでしたが、

wrappedPerson(1:2)

は、wrappedPersonクラスへのコンストラクター呼び出し、またはWrappedPersonの存在しない配列の要素へのアクセスの試みとして解釈されます(Javaでは「()」演算子をオーバーライドできないため)。任意の洞察をいただければ幸いです。

私がJavaクラスに使用しているコードは

public class Person {
  int _age;
  ArrayList<Name> _names;

  public Person(int age, Name name) {
    _age = age;
    _names.add(name);
  }

  public int age() {return _age;}
  public void age(int age) {_age = age;}
  public Name[] name() {return _names.toArray(new Name[0]);}
  public void name(Name name) { _names.add(name);}
}

public class Name {
  String _first;
  String _last;

  public Name(String first, String last) {
    _first = first;
    _last = last;
  }

  public int first() {return _first;}
  public void first(String firstName) {_first = firstName;}
  public int last() {return _last;}
  public void last(String lastName) {_last = lastName;}
}
4

1 に答える 1

6

TL; DR:いくつかの凝ったOOPMコードのトリックでそれは可能です。の動作の変更は()、Javaラッパークラスの上に.定義するMatlabラッパークラスを使用して行うことができます。subsrefしかし、MatlabからJavaへの固有のオーバーヘッドのため、通常のMatlabコードよりも高速になることはおそらくなく、はるかに複雑で面倒です。ロジックをJavaにも移行しない限り、このアプローチではおそらくスピードアップにはなりません。

お手数をおかけして申し訳ございません。

これを完全に理解する前に、Matlabコードから呼び出されたJava構造のパフォーマンスをベンチマークすることができます。Javaフィールドアクセスとメソッド呼び出しは、それ自体でMatlabのものよりもはるかに高速ですが、Mコードから呼び出すにはかなりのオーバーヘッドがあるため、多くのロジックをJavaにプッシュダウンしない限り、最終的には終了する可能性があります。速度が大幅に低下します。MコードをJavaレイヤーにクロスするたびに、料金が発生します。この答えでベンチマークを見てください:MATLAB OOPは遅いですか、それとも私は何か間違ったことをしていますか?規模のアイデアを得るために。(完全な開示:それは私の答えの1つです。)Javaフィールドアクセスは含まれていませんが、オートボクシングのオーバーヘッドのため、おそらくメソッド呼び出しの順序になっています。また、例のように、パブリックフィールドの代わりにgetterメソッドとsetterメソッドを使用して(つまり、「適切な」Javaスタイルで)Javaクラスをコーディングしている場合は、アクセスごとにJavaメソッド呼び出しのコストが発生します。純粋なMatlab構造に比べて悪くなるでしょう。

x = [foo(1:2).bar]とはいえ、Java配列であるMコード内でその構文を機能させたい場合fooは、基本的に可能です。()とは両方とも、.Javaを呼び出す前にMatlabで評価されます。できることは、Java配列ラッパークラスに対応するMatlab OOPで独自のカスタムJavaArrayWrapperクラスを定義し、その中で(おそらくラップされた)Java配列をラップすることです。オーバーライドsubsrefして、とsubsasgnの両方を処理する()ようにします.。の場合()、配列の通常のサブセット化を実行し、JavaArrayWrapperでラップして返します。場合.

  • ラップされたオブジェクトがスカラーの場合は、通常どおりJavaメソッドを呼び出します。
  • ラップされたオブジェクトが配列の場合は、そのオブジェクトをループし、各要素でJavaメソッドを呼び出して、結果を収集します。結果がJavaオブジェクトの場合は、JavaArrayWrapperでラップされたものを返します。

だが。Matlab / Javaの障壁を越えるオーバーヘッドのため、これは遅く、おそらく純粋なMatlabコードよりも桁違いに遅くなります。

これを高速に動作させるには、Java配列をラップし、Java Reflection APIを使用して選択した各配列メンバーオブジェクトのプロパティを抽出し、それらを配列に収集する、対応するカスタムJavaクラスを提供できます。x = foo(1:3).a.b.c重要なのは、Matlabで「連鎖」参照を実行し、オブジェクトである場合、を評価して結果を呼び出すなどfooの段階的な評価を行わないことです。実際には、参照全体を解析し、それを構造化された引数に変換し、チェーン全体を解釈する責任があるのメソッドにすべてを渡します。暗黙の呼び出しは次のようになります。foo(1:3).a(1:3).a.b.csubsreffoo

x = subsref(foo, [ struct('type','()','subs',{{[1 2 3]}}), ...
                   struct('type','.', 'subs','a'), ...
                   struct('type','.', 'subs','b'), ... 
                   struct('type','.', 'subs','c') ] )

したがって、参照「チェーン」全体に事前にアクセスできる場合foo、定義されたMコードラッパークラスであればsubsasgn、その参照全体をJava引数に変換し、Javaラッパーへの単一のメソッド呼び出しで渡すことができます。次に、Java Reflectionを使用して、ラップされた配列を動的に調べ、参照要素を選択し、連鎖参照をすべてJavaレイヤー内で実行するクラス。たとえば、getNestedFields()このようなJavaクラスを呼び出します。

public class DynamicFieldAccessArrayWrapper {
    private ArrayList _wrappedArray;

    public Object getNestedFields(int[] selectedIndexes, String[] fieldPath) {
        // Pseudo-code:
        ArrayList result = new ArrayList();
        if (selectedIndexes == null) {
            selectedIndexes = 1:_wrappedArray.length();
        }
        for (ix in selectedIndexes) {
            Object obj = _wrappedArray.get(ix-1);
            Object val = obj;
            for (fieldName in fieldPath) {
                java.lang.reflect.Field field = val.getClass().getField(fieldName);
                val = field.getValue(val);
            }
            result.add(val);
        }
        return result.toArray(); // Return as array so Matlab can auto-unbox it; will need more type detection to get array type right
    }
}

次に、Mコードラッパークラスが結果を調べて、それがプリミティブっぽく、Matlab配列またはコンマ区切りリスト(つまり、で収集される複数のargout)として返されるか[...]、別のJavaArrayWrapperでラップされるかを決定します。 Mコードオブジェクト。

Mコードラッパークラスは次のようになります。

classdef MyMJavaArrayWrapper < handle
    % Inherit from handle because Java objects are reference-y
    properties
        jWrappedArray  % holds a DynamicFieldAccessArrayWrapper
    end
    methods
        function varargout = subsref(obj, s)
            if isequal(s(1).type, '()')
                indices = s(1).subs;
                s(1) = [];
            else
                indices = [];
            end
            % TODO: check for unsupported indexing types in remaining s
            fieldNameChain = parseFieldNamesFromArgs(s);
            out = getNestedFields( jWrappedArray, indices, fieldNameChain );
            varargout = unpackResultsAndConvertIfNeeded(out);
        end
    end
end

subsasgn呼び出しの値のマーシャリングとアンマーシャリングに伴うオーバーヘッドは、おそらくJavaビットからの速度の向上を圧倒するでしょう。

subsasgnのMコード実装をCで構造のマーシャリングとアンマーシャリングを行うMEX実装に置き換え、JNIを使​​用してJavaオブジェクトを構築し、getNestedFieldsを呼び出し、結果をMatlab構造に変換することで、このオーバーヘッドをおそらくなくすことができます。これは私が例をあげることができるものをはるかに超えています。

これがあなたにとって少し恐ろしいように見えるなら、私は完全に同意します。あなたはここで言語の端にぶつかっています、そしてユーザーランドから言語を拡張しようとすること(特に新しい構文上の振る舞いを提供するために)は本当に難しいです。私は本番コードでこのようなことを真剣に行うことはしません。あなたが見ている問題の領域を概説しようとしているだけです。

これらの深くネストされた構造の同種の配列を扱っていますか?おそらく、それらを「平面組織化」構造に変換することが可能であり、スカラーフィールドを持つ構造体の配列の代わりに、配列フィールドを持つスカラー構造体があります。次に、純粋なMコードでそれらに対してベクトル化された操作を実行できます。これにより、特にオーバーヘッドがmxarrayごとにスケーリングする、saveおよびを使用すると、処理が大幅に高速化されます。load

于 2013-03-20T20:16:50.613 に答える