Какой-либо способ далее оптимизировать Java отражающий вызов метода?

Как уже отмечалось, порядок аргументов в массиве предложения $ in не отражает порядок получения документов. Это, конечно, будет естественный порядок или выбранным порядком индекса, как показано.

Если вам нужно сохранить этот порядок, то у вас в основном есть два варианта.

Итак, скажем, что вы сопоставляли значения _id в своих документах с массивом, который будет передан в $in как [ 4, 2, 8 ].

Подход с использованием Aggregate


var list = [ 4, 2, 8 ];

db.collection.aggregate([

    // Match the selected documents by "_id"
    { "$match": {
        "_id": { "$in": [ 4, 2, 8 ] },
    },

    // Project a "weight" to each document
    { "$project": {
        "weight": { "$cond": [
            { "$eq": [ "$_id", 4  ] },
            1,
            { "$cond": [
                { "$eq": [ "$_id", 2 ] },
                2,
                3
            ]}
        ]}
    }},

    // Sort the results
    { "$sort": { "weight": 1 } }

])

Таким образом, это будет расширенная форма. Что в основном происходит здесь, так это то, что так же, как массив значений передается в $in, вы также создаете «вложенный» $cond оператор для проверки значений и назначения соответствующего веса. Поскольку это «весовое» значение отражает порядок элементов в массиве, вы можете передать это значение на этап сортировки, чтобы получить ваши результаты в требуемом порядке.

Конечно, вы действительно «строите» «оператор конвейера в коде, что-то вроде этого:

var list = [ 4, 2, 8 ];

var stack = [];

for (var i = list.length - 1; i > 0; i--) {

    var rec = {
        "$cond": [
            { "$eq": [ "$_id", list[i-1] ] },
            i
        ]
    };

    if ( stack.length == 0 ) {
        rec["$cond"].push( i+1 );
    } else {
        var lval = stack.pop();
        rec["$cond"].push( lval );
    }

    stack.push( rec );

}

var pipeline = [
    { "$match": { "_id": { "$in": list } }},
    { "$project": { "weight": stack[0] }},
    { "$sort": { "weight": 1 } }
];

db.collection.aggregate( pipeline );

Подход с использованием mapReduce


Конечно, если все это кажется вам полезным для вашей чувствительности, вы можете сделать то же самое, используя mapReduce, который выглядит проще, но, скорее всего, будет работать несколько медленнее.

var list = [ 4, 2, 8 ];

db.collection.mapReduce(
    function () {
        var order = inputs.indexOf(this._id);
        emit( order, { doc: this } );
    },
    function() {},
    { 
        "out": { "inline": 1 },
        "query": { "_id": { "$in": list } },
        "scope": { "inputs": list } ,
        "finalize": function (key, value) {
            return value.doc;
        }
    }
)

И это в основном полагается на испускаемые «ключевые» значения, находящиеся в «индексном порядке» того, как они встречаются во входе array.


Таким образом, это, по сути, ваши способы поддержания порядка списка входных данных в $in, когда у вас уже есть этот список в определенном порядке.

20
задан Nicholas 5 January 2009 в 22:54
поделиться

5 ответов

Комментарии ниже касаются реализации Sun, в особенности OpenJDK 6. Ваш пробег может меняться в зависимости от других реализаций платформы Java.

java.lang.Class делает некоторое кэширование себя, так реализация Вашего собственного кэша не может улучшить вещи очень. Сделайте тесты синхронизации с и без ручного кэширования.

фактический механизм вызова оптимизирован также. Первые 15 выполнений (по умолчанию) Вашего отраженного метода называют с помощью JNI; после этого байт-код сгенерирован и вызов, который отразил, что метод будет работать тождественно к вызову того метода непосредственно в коде Java.

55
ответ дан 29 November 2019 в 22:47
поделиться

Я запустил некоторые тесты вокруг ответа и использования Chris Jester-Young подробный опции, я определенно заметил, что компилятор принимает некоторые меры вокруг 15-го вызова. Трудно, чтобы сказать, существует ли много дифференциала производительности без более сложного теста, но это убедительно. Вот вывод:

Test# 0
Test# 1
Test# 2
Test# 3
Test# 4
Test# 5
Test# 6
Test# 7
Test# 8
Test# 9
Test# 10
Test# 11
Test# 12
Test# 13
Test# 14
[Loaded sun.reflect.ClassFileConstants from C:\jdk1.5.0_06\jre\lib\rt.jar]
[Loaded sun.reflect.AccessorGenerator from C:\jdk1.5.0_06\jre\lib\rt.jar]
[Loaded sun.reflect.MethodAccessorGenerator from C:\jdk1.5.0_06\jre\lib\rt.jar]
[Loaded sun.reflect.ByteVectorFactory from C:\jdk1.5.0_06\jre\lib\rt.jar]
[Loaded sun.reflect.ByteVector from C:\jdk1.5.0_06\jre\lib\rt.jar]
[Loaded sun.reflect.ByteVectorImpl from C:\jdk1.5.0_06\jre\lib\rt.jar]
[Loaded sun.reflect.ClassFileAssembler from C:\jdk1.5.0_06\jre\lib\rt.jar]
[Loaded sun.reflect.UTF8 from C:\jdk1.5.0_06\jre\lib\rt.jar]
[Loaded java.lang.Void from C:\jdk1.5.0_06\jre\lib\rt.jar]
[Loaded sun.reflect.Label from C:\jdk1.5.0_06\jre\lib\rt.jar]
[Loaded sun.reflect.Label$PatchInfo from C:\jdk1.5.0_06\jre\lib\rt.jar]
[Loaded java.util.AbstractList$Itr from C:\jdk1.5.0_06\jre\lib\rt.jar]
[Loaded sun.reflect.MethodAccessorGenerator$1 from C:\jdk1.5.0_06\jre\lib\rt.jar]
[Loaded sun.reflect.ClassDefiner from C:\jdk1.5.0_06\jre\lib\rt.jar]
[Loaded sun.reflect.ClassDefiner$1 from C:\jdk1.5.0_06\jre\lib\rt.jar]
[Loaded sun.reflect.GeneratedMethodAccessor1 from __JVM_DefineClass__]
Test# 15
Test# 16
Test# 17

я предполагаю , бизнес InvokeDynamic не притягивает слишком много разработчиков на основе отражательного ускорения/устранения.

Спасибо Chris.

8
ответ дан 29 November 2019 в 22:47
поделиться

Вы определенно захотите отразить, что метод возражает только однажды (вероятно, как частные помехи), и использование, что для вызова, а не отражают его каждый раз. Не беспокойтесь картой кэша, если Вы не знаете имя во время компиляции.

, Если это разумно в Вашем контексте, Вы можете хотеть держаться за и снова использовать объект массива аргументов (не забывайте аннулировать элементы массива на выходе метода для предотвращения временного ингибирования GC).

, Если всегда вызвано с теми же детскими колясками (очень вряд ли), Вы могли бы зависнуть на детские коляски и (массив аргументов с, он - значения), снова используют их.

я ничего не делал бы попытку кроме того по причинам, уже приведенным другими ответами.

1
ответ дан 29 November 2019 в 22:47
поделиться

Преждевременная Оптимизация обычно плоха. Независимо от того, что, Ваша производительность все еще много раз будет производительностью динамического языка, таким образом, я действительно не волновался бы об этом вне документирования того, что это использует отражение и поэтому могло бы быть субоптимальным.

кроме того, существует хороший шанс, что или теперь или в будущем, Java оптимизирует байт-код так, чтобы вызов не стоил чего-то большего чем вызова метода при использовании в цикле. Ваша "Оптимизация" может на самом деле препятствовать способности к компиляторам сделать что-то как этот. (Я знаю, что я неопределенен, но это произошло - МНОГО).

0
ответ дан 29 November 2019 в 22:47
поделиться

Если стоимость вызова составляет меньше чем 10% стоимости того, что продолжается в методе, об этом едва стоит вызвать беспокойство.

можно решить это путем выполнения его 10^6 времена в цикле, с и без кишок стандартной программы. Время это с секундомером, таким образом, секунды переводят в микросекунды.

0
ответ дан 29 November 2019 в 22:47
поделиться
Другие вопросы по тегам:

Похожие вопросы: