Как выполнять несколько моделей параллельно, а не последовательно?

У меня есть разные модели, и я выполняю эти модели одну за другой последовательно. У меня будет около 200 моделей.

Ниже приведен мой код, в котором я выполняю эти модели одну за другой.

Map<String, List<ServerMetrics>> metricsHolder = new HashMap<String, List<ServerMetrics>>();

for (String alias : serverNames) {
    List<ClientsModel> modelMetadata = getModelAttributes();
    List<MachineInfo> machineInfo = getMachineInfo();

    List<ServerMetrics> metricsList = new ArrayList<ServerMetrics>();

    // calling model one by one sequentially
    // is there any way to make this multithreaded?
    // here modelMetadata size might be 100 or 200
    for (ClientsModel modelList : modelMetadata) {
        String modelValue = modelList.getModelValue();
        String modelId = String.valueOf(modelList.getModelId());

        // execute my model here and storing the metrics in the metricsList object
        ServerMetrics metrics = TestUtils.executeModelMetrics(machineInfo, modelValue);
        metrics.setModelId(modelId);

        metricsList.add(metrics);
    }

    metricsHolder.put(alias, dynMetricsList);
}

Постановка проблемы:-

Есть ли способ сделать выполнение модели многопоточным, а затем сохранить результат в объект metricsList?


person john    schedule 18.01.2015    source источник
comment
Если выполнения не являются взаимозависимыми, вы можете просто создать новый поток для каждого из них, а затем сохранить результат. Не можешь?   -  person Shivam Verma    schedule 18.01.2015
comment
Если у меня около 200 моделей, то вы хотите, чтобы я породил 200 тем?   -  person john    schedule 18.01.2015


Ответы (1)


Если в вашем коде нет условий гонки данных (многопоточный доступ к одним и тем же данным, которые не синхронизированы должным образом), вы можете использовать пул потоков в форме ExecutorService для запуска Callable реализаций в потоках. Вы можете выполнять работу в Callable.

В основном потоке ExecutorService возвращает Future, который вы можете дождаться после создания всех задач.

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

    Map<String, List<ServerMetrics>> metricsHolder = new HashMap<String, List<ServerMetrics>>();
    // Size of thread pool set at 10 - can be increased but increasing it 
    // to more than the number of cores on your computer is probably not 
    // useful, as it seems like your task is CPU-bound
    ExecutorService executorService = Executors.newFixedThreadPool(10);

    for (String alias : serverNames) {
        List<ClientsModel> modelMetadata = getModelAttributes();
        List<MachineInfo> machineInfo = getMachineInfo();

        List<Future<ServerMetrics>> metricsFutureList = new ArrayList<Future<ServerMetrics>>();

        // calling model one by one sequentially
        // is there any way to make this multithreaded?
        for (ClientsModel modelList : modelMetadata) {
            final String modelValue = modelList.getModelValue();
            final String modelId = String.valueOf(modelList.getModelId());

            metricsFutureList.add(executorService.submit(new Callable<ServerMetrics>() {
                @Override
                public ServerMetrics call() throws Exception {

                    // execute my model here and storing the metrics in the list
                    ServerMetrics metrics = TestUtils.executeModelMetrics(machineInfo, modelValue);
                    metrics.setModelId(modelId);
                    return metrics;
                }
            }));

        }
        List<ServerMetrics> metricsList = new ArrayList<ServerMetrics>();
        for (Future<ServerMetrics> future : metricsFutureList) {
            metricsList.add(future.get());
        }
        metricsHolder.put(alias, dynMetricsList);
    }
person Erwin Bolwidt    schedule 18.01.2015
comment
Спасибо за хорошее предложение. В своей первой строке вы упомянули что-то о If there are no data race conditions, что может вызвать проблему в моем коде, как вы понимаете? - person john; 18.01.2015
comment
Если модели работают с одними и теми же данными (хотя бы один метод executeModelMetrics обновляет данные, которые читает хотя бы один другой executeModelMetrics), то вам нужно задуматься о многопоточных методах синхронизации. Если несколько вызовов executeModelMetrics работают с совершенно разными объектами Java или они не изменяют объекты Java (это нормально, если все значения были установлены до запуска потока), то у вас нет проблемы. - person Erwin Bolwidt; 18.01.2015
comment
@ErwinBolwidt Да, в моем случае executeModelMetrics работают с разными объектами Java, и они не будут изменять объекты Java, так что все должно быть в порядке. - person john; 18.01.2015
comment
Но ему нужно синхронизировать доступ к своему metricsHolder; это может быть повреждено put() в нескольких потоках. Это делает его безопасным: Map<String, List<ServerMetrics>> metricsHolder = Collections.synchronizedMap(new HashMap<String, List<ServerMetrics>>()); - person gknicker; 18.01.2015
comment
@gknicker Не совсем, так как metricsHolder не доступен в нескольких потоках (только в основном потоке) - person Erwin Bolwidt; 19.01.2015
comment
@ErwinBolwidt Хм. Спасибо, что поправили меня. Однако я не вижу особых преимуществ в одновременном выполнении метрик на одном сервере. Было бы гораздо больше пользы от одновременного выполнения метрик на нескольких серверах. - person gknicker; 19.01.2015