Java как перебирать все значения HashMap параллельно - PullRequest
1 голос
/ 09 мая 2020

У меня есть HashMap с ключом типа HashSet и значением типа ArrayList.

После того, как все пары "ключ-значение" вставлены в Map. Я хочу перебрать каждый ключ и его значение для дальнейшего процесса, а не только для печати, он будет использоваться в дальнейшем процессе, где ключ и значения передаются как параметры String.

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

Я пробовал Stream API, но он печатает только все значения итераций параллельно, но в дальнейшем процессе он не делает то, что я ожидаю, возможно, я что-то делаю неправильно, поскольку я не знаком с потоками. Если это не может быть достигнуто с помощью доступных встроенных функций или классов, то подойдут даже сторонние Jar-файлы (Apache -commons).

Это код, который я пробовал до сих пор:

String jobId = "J1";
Map<Set<String>,List<String>> map_batch_result_details = new HashMap<Set<String>,List<String>>();
Set<String> hs_batchesId= new HashSet<String>();
List<String> list_resultId = new ArrayList<String>();

hs_batchesId.add("B1"); 
hs_batchesId.add("B2"); 
hs_batchesId.add("B3");

list_resultId.add("R1");
list_resultId.add("R2");
list_resultId.add("R3");


map_batch_result_details.put(hs_batchesId, list_resultId); 

map_batch_result_details.entrySet().stream().forEach(e -> {
System.out.format("key: %s, value: %s%n", e.getKey(), e.getValue());  // for printing results using stream without iterating each row sequentially instead iterates it parallely

 InputStream inputStream =  Connection.getQueryResultStream(jobId, e.getKey().toString(), e.getValue().toString());
/*
getQueryResultStream expects one batchId which is  <Key> of Map but it needs it in String so I am using toString
similarly third parameter expects one resultId which is <value> of Map again in String so toString
But Code fails as it is not passing 1 key and 1 value, rather it passes all key values at once in single call.
*/

});

Выход

CALL: getQueryResultStream(jobId, e.getKey().toString(),e.getValue().toString());

**Actual values passed**
 getQueryResultStream(J1,[B1,B2,B3],[R1,R2,R3])

**Expected values**
getQueryResultStream(J1,B1,R1)
getQueryResultStream(J1,B2,R2)
getQueryResultStream(J1,B3,R3)

Expected value should execute in Parallel without having to wait for first iteration to get over. But not in one call which is happening in Actual values.

1 Ответ

0 голосов
/ 11 мая 2020

У меня есть HashMap с ключом типа HashSet и значением типа ArrayList.

Вот в чем проблема. Единственная запись, независимо от того, что находится внутри ключа / значения. Более того, эта структура не гарантирует, что "B1" и "R1" связаны вместе, пока HashSet не упорядочен.

Я рекомендую использовать другую структуру. Вы использовали Map только с одной записью, имеющей как ключ, так и значение в качестве коллекции, что непрактично для одновременной итерации.

Я рекомендую использовать список либо пользовательского, либо любого импортированного класса Pair<T, R> (с Методы получения говорят first и second) или Entry<K, V>, которые работают одинаково:

List<Entry<String, String>> entries = new ArrayList<>();
entries.add(new SimpleEntry<>("B1", "R1"));
entries.add(new SimpleEntry<>("B2", "R2"));
entries.add(new SimpleEntry<>("B3", "R3"));

entries.parallelStream()
       .forEach(e -> System.out.format("key: %s, value: %s%n", e.getKey(), e.getValue()));

Пока поток параллелен, вывод forEach неупорядочен и выглядит случайным. Пример вывода:

key: B2, value: R2
key: B1, value: R1
key: B3, value: R3

Кстати, вы можете продолжить потоковую передачу вместо использования forEach:

entries.parallelStream()
       .map(e-> Connection.getQueryResultStream(jobId, e.getKey(), e.getValue()))
       ...

Edit : Если введено Map<Set<String>, List<String>> и вы не можете его изменить, вы конвертируете его в List<Entry<String, String>>, используя следующий фрагмент. Единственная надежда состоит в том, что Set - это LinkedHashSet, который поддерживает порядок, и связь между ключом и значением будет сохраняться в соответствии с намерениями:

map_batch_result_details.forEach((k, v) -> {
    Iterator<String> keysIterator = k.iterator();
    Iterator<String> valuesIterator = v.iterator();
    while (keysIterator.hasNext() && valuesIterator.hasNext()) {
        String key = keysIterator.next();
        String value = valuesIterator.next();
        entries.add(new SimpleEntry<>(key, value));
        }
    }
);
...