Выполнение методов из одного класса параллельно с минимальными издержками

1

У меня есть алгоритм класса, который имеет 2 сложных, трудоемких метода, например method1 и method2. Я должен создать несколько экземпляров этого класса, и запрос соответственно. метод1 и метод 2 для каждого из этих экземпляров параллельно. Следующий код в значительной степени позволяет:

private final List<Algorithm> algorithms;

private final ExecutorService executor;
private final List<Future<Void>> futures;

public AlgorithmManager(List<Algorithm> algorithms){
    this.algorithms=algorithms;

    //Define workers
    executor = Executors.newFixedThreadPool(Constants.MAXTHREADS); //Creates a threat pool consisting of MAXTHREADS threats
    futures=new ArrayList<Future<Void>>(algorithms.size());
}

/**
 * Procedure to solve method1 for each algorithm in parallel
 */
public double[] solveMethod1(){
    double[] results=new double[algorithms.size()];
    List<FutureTask<Double>> taskList=new ArrayList<FutureTask<Double>>();

    //submit all the relevant tasks to solve method1
    for(Algorithm pp : algorithms){
        FutureTask<Double> futureTask = new FutureTask<Double>(new Callable<Double>() {
            @Override
            public Double call() {
                return pp.solveMethod1();  //SolveMethod1
            }
        });

        taskList.add(futureTask);
        executor.submit(futureTask);
    }

    //Query the results of each task one by one
    for(int i=0; i<algorithms.size(); i++){
        results[i]=taskList.get(i).get();
    }

    return results;
}

/**
 * Procedure to solve method2 for each algorithm in parallel
 */
public int[] solveMethod2(){
    int[] results=new double[algorithms.size()];
    List<FutureTask<Integer>> taskList=new ArrayList<FutureTask<Integer>>();

    //submit all the relevant tasks to solve method1
    for(Algorithm pp : algorithms){
        FutureTask<Integer> futureTask = new FutureTask<Integer>(new Callable<Integer>() {
            @Override
            public Integer call() {
                return pp.solveMethod2();  //SolveMethod2
            }
        });

        taskList.add(futureTask);
        executor.submit(futureTask);
    }

    //Query the results of each task one by one
    for(int i=0; i<algorithms.size(); i++){
        results[i]=taskList.get(i).get();
    }

    return results;
}

Вещь, которая беспокоит меня, - это накладные расходы, вызванные создаваемыми объектами FutureTask каждый раз при вызове методаMethod1 или solveMethod2 (это происходит очень часто!). Проблема в том, что, согласно JavaDoc, вы не можете повторно использовать объект FutureTask, т.е. Я не могу выполнить один и тот же FutureTask несколько раз, поэтому мне нужно создать новый экземпляр объекта каждый раз, когда я хочу выполнить любой из этих методов. Я подумал о том, чтобы сделать класс Алгоритм вызываемым, тем самым добавив метод:

@Override
public Double call() throws Exception {
    return this.method1();
}

Таким образом, я могу просто представить экземпляры Algorithm для исполнителя, но я могу сделать это только для одного метода? Любые предложения о том, как улучшить эту реализацию, чистым и эффективным образом? К сожалению, нежелательно ставить method1 и method2 на 2 разных класса, поскольку они сильно зависят от структур данных друг от друга.

Btw, это упрощенный фрагмент кода. В моем реальном коде методы method1 и method2 также могут генерировать исключения.

  • 2
    Не поймите меня неправильно, но ваш ответ «беспокоиться о накладных расходах» - неправильный подход. Если вы считаете, что у вас проблемы с производительностью, проанализируйте поведение приложения во время выполнения, чтобы действительно понять, что происходит. Другими словами: действительно ли вы думаете, что накладные расходы на создание нескольких объектов вступят в игру, когда ваши фактические вычисления настолько сложны? Не начинайте «оптимизировать» свой код, не понимая, в чем заключается ваша настоящая проблема. См. C2.com/cgi/wiki?PrematureOptimization
  • 0
    Зачастую программирование чего-то небрежного и правильное программирование требуют примерно одинаковых усилий. Поскольку я часто использую свой код, я с самого начала учусь правильно его реализовывать. Отсюда и мой вопрос. Кроме того, я согласен, что это, безусловно, не будет узким местом моей реализации.
Теги:
parallel-processing

1 ответ

1
Лучший ответ

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

Callable<Double> c = new Callable<Double> () { ... };
Future<Double> f = executor.submit(c);
Double result = f.get();
  • 0
    Отлично, это действительно чище, и нет необходимости перераспределять новые объекты. Спасибо!

Ещё вопросы

Сообщество Overcoder
Наверх
Меню