2012-02-26 2 views
6

Я пытаюсь перебрать Java-итератор одновременно, но у меня проблемы с лучшим способом сделать это.Java Iterator Concurrency

Вот что у меня есть, где я не пытаюсь делать что-либо одновременно.

Long l;  
Iterator<Long> i = getUserIDs(); 

while (i.hasNext()) { 
    l = i.next(); 

    someObject.doSomething(l); 
    anotheObject.doSomething(l); 
} 

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

Заранее спасибо.

ответ

4

Одним из решений является использование исполнителя для параллелизации вашей работы.

Простой пример:

ExecutorService executor = Executors.newCachedThreadPool(); 

Iterator<Long> i = getUserIDs(); 
while (i.hasNext()) { 
    final Long l = i.next(); 

    Runnable task = new Runnable() { 
     public void run() { 
      someObject.doSomething(l); 
      anotheObject.doSomething(l); 
     } 
    } 

    executor.submit(task); 
} 

executor.shutdown(); 

Это создаст новый поток для каждого элемента в итератора, который будет делать эту работу. Вы можете настроить, сколько потоков используется с помощью другого метода в классе Executors, или разделить работу по своему усмотрению (например, другой для каждого вызова метода).

5

А может предложить два возможных подхода:

  • Используйте пул потоков и направить элементы, полученные от итератора к набору для обработки потоков. Это не ускорит операции итератора, поскольку они все равно будут выполняться в одном потоке, но будут распараллеливать фактическую обработку.

  • В зависимости от того, как создается итерация, вы могли бы быть в состоянии разделить итерационный процесс на несколько сегментов, каждый из которых обрабатывается отдельным потоком через другой Iterator объекта. Например, посмотрите на методы List.sublist(int fromIndex, int toIndex) и List.listIterator(int index).

    Это позволит выполнять операции итератора параллельно, но не всегда возможно сегментировать итерацию, как это, как правило, из-за простого факта, что элементы, подлежащие повторению, не доступны сразу.

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

Самый важный совет в этом случае заключается в следующем: «Используйте профайлер», как правило, должны придерживаться «Не оптимизировать преждевременно». Используя профилировщик, такой как VisualVM, вы должны быть в состоянии установить точные причины любых проблем с производительностью, не снимая снимки в темноте.

1

Если вы используете Java 7, вы можете использовать новый fork/join; см. tutorial.

Он не только автоматически разбивает задачи между потоками, но если какой-то поток заканчивает свои задачи раньше других потоков, он «крадет» некоторые задачи из других потоков.