并行化双嵌套 for 循环
Parallelizing double nested for loop
我有一个非常大的列表,所以我需要加快整体速度,我正在尝试并行化这个 for 循环:
public HashMap<String, String> getData()
{
//Both list are ArrayList<String>
HashMap<String, String> hashMap = new HashMap<>();
for (int w = 0; w < firstList.size(); w++) {
boolean once = false;
for (int j = 0; j < secondList.size(); j++) {
if (!once && secondList.get(j).var.startsWith(firstList.get(w).var.toLowerCase())) {
hashMap.put(firstList.get(w).var, secondList.get(j).var);
once = true;
}
}
}
return hashMap;
}
我找到了这个很好的答案 Parallelizing a for loop,但不太明白如何将它应用到我的案例中,我应该为我的 [=13] 的 <K, V>
创建两个 Callable <output>
=] ?
还是我用这个方法做错了?
我会先用流重写它。这不仅会使代码可并行化,还会使其更具可读性。它还将避免原始代码中出现的所有重复,并确保以最佳方式迭代列表:
private static final class Entry {
private final String first;
private final String second;
// constructor, getters left as an exercise
}
public Map<String, String> getData() {
return firstList.stream()
.flatMap(firstListElement -> {
String lowercase = firstListElement.toLowerCase();
return secondList.stream()
.filter(secondListElement -> secondListElement.startsWith(lowercase))
.limit(1)
.map(secondListElement -> new Entry(firstListElement, secondListElement));
})
.collect(Collectors.toMap(Entry::getFirst, Entry::getSecond));
}
然后我会测量执行它所花费的时间,并比较执行相同代码所花费的时间,但与 firstList.parallelStream()
不同。
像这样的事情会并行完成工作(在外部列表上)。但是对于只有 281 个的列表,这可能不会增加太多价值。
在内部列表中,如果重要的是找到一个匹配项,而不是第一个匹配项,那么该工作也可以并行化,这更有可能产生重大影响。
final ConcurrentMap<String, String> results = new ConcurrentHashMap<>();
firstList.stream()
.unordered()
.parallel()
.map(v1 -> v1.var)
.forEach(var -> {
final String lowerVar1 = var.toLowerCase();
secondList.stream()
.filter(v2 -> v2.var.startsWith(lowerVar1))
.findFirst()
.ifPresent(v2 -> results.put(var, v2.var);
});
问题不在于如何并行化循环。您使用了错误的方法。
如果我理解正确的话,您希望列表 1 的每个元素都添加列表 2 中以相同字符串开头的 hashmap 1 条目。
首先,我不明白为什么在找到匹配项并使用 once
变量时不跳出循环。
另外为什么你需要 once
变量,因为你可以检查 list1 的单词是否已经存在于 hashmap 中?
无论如何,您应该使用 TreeMap(检查 NavigableMap 接口)而不是检查紧密匹配的哈希图。
另外,为什么你不能在创建列表时首先执行此逻辑?
也许您正在尝试优化错误的东西?
我有一个非常大的列表,所以我需要加快整体速度,我正在尝试并行化这个 for 循环:
public HashMap<String, String> getData()
{
//Both list are ArrayList<String>
HashMap<String, String> hashMap = new HashMap<>();
for (int w = 0; w < firstList.size(); w++) {
boolean once = false;
for (int j = 0; j < secondList.size(); j++) {
if (!once && secondList.get(j).var.startsWith(firstList.get(w).var.toLowerCase())) {
hashMap.put(firstList.get(w).var, secondList.get(j).var);
once = true;
}
}
}
return hashMap;
}
我找到了这个很好的答案 Parallelizing a for loop,但不太明白如何将它应用到我的案例中,我应该为我的 [=13] 的 <K, V>
创建两个 Callable <output>
=] ?
还是我用这个方法做错了?
我会先用流重写它。这不仅会使代码可并行化,还会使其更具可读性。它还将避免原始代码中出现的所有重复,并确保以最佳方式迭代列表:
private static final class Entry {
private final String first;
private final String second;
// constructor, getters left as an exercise
}
public Map<String, String> getData() {
return firstList.stream()
.flatMap(firstListElement -> {
String lowercase = firstListElement.toLowerCase();
return secondList.stream()
.filter(secondListElement -> secondListElement.startsWith(lowercase))
.limit(1)
.map(secondListElement -> new Entry(firstListElement, secondListElement));
})
.collect(Collectors.toMap(Entry::getFirst, Entry::getSecond));
}
然后我会测量执行它所花费的时间,并比较执行相同代码所花费的时间,但与 firstList.parallelStream()
不同。
像这样的事情会并行完成工作(在外部列表上)。但是对于只有 281 个的列表,这可能不会增加太多价值。
在内部列表中,如果重要的是找到一个匹配项,而不是第一个匹配项,那么该工作也可以并行化,这更有可能产生重大影响。
final ConcurrentMap<String, String> results = new ConcurrentHashMap<>();
firstList.stream()
.unordered()
.parallel()
.map(v1 -> v1.var)
.forEach(var -> {
final String lowerVar1 = var.toLowerCase();
secondList.stream()
.filter(v2 -> v2.var.startsWith(lowerVar1))
.findFirst()
.ifPresent(v2 -> results.put(var, v2.var);
});
问题不在于如何并行化循环。您使用了错误的方法。
如果我理解正确的话,您希望列表 1 的每个元素都添加列表 2 中以相同字符串开头的 hashmap 1 条目。
首先,我不明白为什么在找到匹配项并使用 once
变量时不跳出循环。
另外为什么你需要 once
变量,因为你可以检查 list1 的单词是否已经存在于 hashmap 中?
无论如何,您应该使用 TreeMap(检查 NavigableMap 接口)而不是检查紧密匹配的哈希图。
另外,为什么你不能在创建列表时首先执行此逻辑?
也许您正在尝试优化错误的东西?