Использование Java Stream вместо цикла for пропускает выполнение кода - PullRequest
0 голосов
/ 23 декабря 2018

Переключение набора циклического кода для использования параллельного потока, по-видимому, приводит к игнорированию определенной части кода.

Я использую MOA и Weka с Java 11 для выполнения простой рекомендацииПример движка, использующий подсказки из исходного кода moa.tasks.EvaluateOnlineRecomender, который использует внутреннюю настройку задачи MOA для проверки точности реализации смещенной регуляризованной пошаговой одновременной матричной факторизации (BRISMF), предоставленной MOA.Вместо того, чтобы использовать подготовленный класс MOA MovielensDataset, я переключился на Instances Weka для перспектив применения инструментов ML от Weka.

Время, необходимое для обработки около миллиона экземпляров (я использую Movielens 1Mнабор данных) было около 13-14 минут.В попытке увидеть улучшения, я хотел запустить его в параллельном потоке и стал подозрительным, когда задача завершилась примерно через 40 секунд.Я обнаружил, что BRISMFPredictor.predictRating всегда производит 0 в теле параллельного потока.Вот код для любого случая:

Код для инициализации:

import com.github.javacliparser.FileOption;
import com.github.javacliparser.IntOption;

import moa.options.ClassOption;
import moa.recommender.predictor.BRISMFPredictor;
import moa.recommender.predictor.RatingPredictor;
import moa.recommender.rc.data.RecommenderData;
import weka.core.converters.CSVLoader;

...

private static ClassOption datasetOption;
private static ClassOption ratingPredictorOption;
private static IntOption sampleFrequencyOption;
private static FileOption defaultFileOption;

static {
    ratingPredictorOption = new ClassOption("ratingPredictor",
            's', "Rating Predictor to evaluate on.", RatingPredictor.class,
            "moa.recommender.predictor.BRISMFPredictor");
    sampleFrequencyOption = new IntOption("sampleFrequency",
            'f', "How many instances between samples of the learning performance.", 100, 0, 2147483647);
    defaultFileOption = new FileOption("file",
            'f', "File to load.",
            "C:\\Users\\shiva\\Documents\\Java-ML\\mlapp\\data\\ml-1m\\ratings.dat", "dat", false);
}

... и внутри main() (причуды сCSVLoader от Weka требовал, чтобы я заменял разделитель :: по умолчанию на +)

    var csvLoader = new CSVLoader();
    csvLoader.setSource(defaultFileOption.getFile());
    csvLoader.setFieldSeparator("+");
    var dataset = csvLoader.getDataSet();
    System.out.println(dataset.toSummaryString());

    var predictor = new BRISMFPredictor();
    predictor.prepareForUse();

    RecommenderData data = predictor.getData();
    data.clear();
    data.disableUpdates(false);

Теперь чередуем следующие фрагменты:

for (var instance : dataset) {
    var user = (int) instance.value(0);
    var item = (int) instance.value(1);
    var rating = instance.value(2);

    double predictedRating = predictor.predictRating(user, item);

    System.out.printf("User %d | Movie %d | Actual Rating %d | Predicted Rating %f%n",
                    user, item, Math.round(rating), predictedRating);
}

(теперь это нубво всем одновременно):

dataset.parallelStream().forEach(instance -> {
    var user = (int) instance.value(0);
    var item = (int) instance.value(1);
    var rating = instance.value(2);

    double predictedRating = predictor.predictRating(user, item);

    System.out.printf("User %d | Movie %d | Actual Rating %d | Predicted Rating %f%n",
                    user, item, Math.round(rating), predictedRating);
});

Теперь я решаю, что, черт возьми, эта операция не может быть выполнена параллельно, и я переключаю ее на использование stream().Даже в этом случае сегмент, по-видимому, полностью игнорируется, поскольку вывод снова равен 0.0 каждый раз

dataset.stream().forEach(instance -> {
    var user = (int) instance.value(0);
    var item = (int) instance.value(1);
    var rating = instance.value(2);

    double predictedRating = predictor.predictRating(user, item);

    System.out.printf("User %d | Movie %d | Actual Rating %d | Predicted Rating %f%n",
                    user, item, Math.round(rating), predictedRating);
});

Я пытался удалить оператор печати из прогона, но безрезультатно.

Очевидно,Я получаю ожидаемые выходные строки, состоящие из фактического и прогнозируемого рейтинга в течение 13 минут в первом случае, но обнаруживаю, что прогнозируемый рейтинг равен 0,0 во втором случае с подозрительно низким временем выполнения.Есть что-то, что я пропускаю?

РЕДАКТИРОВАТЬ: использование dataset.forEach() делает то же самое.Возможно, причуды лямбд?

...