我正在嘗試使用多執行緒對存盤在地圖中的陣列進行排序。有大量記錄,約 310 萬條,因此當我嘗試在單執行緒 for 回圈中對這些記錄進行排序時,需要花費數小時才能完成。我希望盡可能縮短這段時間,最好在幾分鐘內(請不要笑!)。
堆疊跟蹤:
Exception in thread "main" java.lang.IllegalArgumentException: java.lang.IllegalArgumentException: Comparison method violates its general contract!
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480)
at java.base/java.util.concurrent.ForkJoinTask.getThrowableException(ForkJoinTask.java:562)
at java.base/java.util.concurrent.ForkJoinTask.reportException(ForkJoinTask.java:591)
at java.base/java.util.concurrent.ForkJoinTask.invoke(ForkJoinTask.java:689)
at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateParallel(ForEachOps.java:159)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateParallel(ForEachOps.java:173)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:233)
at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596)
at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:765)
at com.salesforce.process.Process.startProcess(Process.java:51)
at com.salesforce.process.Schedule.main(Schedule.java:10)
Caused by: java.lang.IllegalArgumentException: Comparison method violates its general contract!
at java.base/java.util.TimSort.mergeLo(TimSort.java:781)
at java.base/java.util.TimSort.mergeAt(TimSort.java:518)
at java.base/java.util.TimSort.mergeCollapse(TimSort.java:448)
at java.base/java.util.TimSort.sort(TimSort.java:245)
at java.base/java.util.Arrays.sort(Arrays.java:1307)
at java.base/java.util.ArrayList.sort(ArrayList.java:1721)
at com.salesforce.process.Process.lambda$startProcess$0(Process.java:51)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
at java.base/java.util.HashMap$ValueSpliterator.forEachRemaining(HashMap.java:1779)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
at java.base/java.util.stream.ForEachOps$ForEachTask.compute(ForEachOps.java:290)
at java.base/java.util.concurrent.CountedCompleter.exec(CountedCompleter.java:754)
at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373)
at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1182)
at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1655)
at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1622)
at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165)
類物件:
public class MyObject {
private Integer id;
public String someString;
public Double sortableValue;
... contructors & getters and setters ...
public static Comparator<MyObject> SortableValueComparator = new Comparator<MyObject>() {
public int compare(MyObject ds1, MyObject ds2) {
Double sortableValue1 = ds1.getSortableValue();
Double sortableValue2 = ds2.getSortableValue();
//descending order
if (Double.compare(sortableValue1, sortableValue2) == 0) {
return 0;
}
else if (Double.compare(sortableValue1, sortableValue2) < 0) {
return -1;
}
else {
return 1;
}
}
};
代碼:
我試圖在這樣的代碼中執行它:
Map<String,List<MyObject>> map = new HashMap<String,List<MyObject>>();
// inject 3.1 million keys with List<MyObject> values, with 1-10 items in each list.
map.values().parallelStream().forEach(list -> list.sort(MyObject.SortableValueComparator));
注意:這不是我想要做的,但我最初是這樣寫的代碼并且它有效。也就是說,如果我這樣做,我的比較器就可以作業。
for (List<MyObject> list : map.values()) {
Collections.sort(list, MyObject.SortableValueComparator);
}
however, it takes for.ev.er to complete, which sadly is not acceptable for our business case. What can this noob do to make this parallelStream() or some way of threading this work?? If you need more info, please let me know! Thanks so much!!
Edit: I want to also give you guys a sample of the data below.
So this is a Map<String,List<MyObject>>.
key (String): "key1", values (List<MyObject>): [{"a",0.0112},{"b",0.12},{"c",0.00512}]
key: "key2", values: [{"d",0.0922},{"a",0.0112},{"f",0.23}]
key: "key3", values: [{"z",0.141},{"w",0.432},{"x",0.0001}]
so, If I wanted to sort key3 list of objects, they would return like this:
key: "key3", values: [{"w",0.432},{"z",0.141},,{"x",0.0001}]
and, I want to do this sort function on every record.
uj5u.com熱心網友回復:
最好在拋出例外的地方放置一個斷點并檢查正在比較的值。然后撰寫一個單元測驗,檢查將這些值傳遞給比較器時會發生什么以及結果如何與相同兩個物件上的“等于”進行比較。這是非常有可能的是“平等”的比較將回傳對于不也是物件0值-即實施“等于”上的MyObject比較比其他sortableValue東西。這在合并集合時會導致問題。
因此,設定一個斷點,查看哪些值破壞了合同,在一兩次測驗中捕獲它。一旦你弄清楚了,你可能需要在比較器中添加一些額外的欄位(如果你不能控制'equals'或者這是你不能改變的現有代碼)到你的比較器使“等于”匹配。
uj5u.com熱心網友回復:
而不是使用
Map.values().parallelStream().forEach(list -> list.sort(comparator))
我用了
Map.values().Stream().forEach(list -> list.sort(comparator))
它奏效了!
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/408346.html
標籤:
上一篇:從樹中洗掉一條邊以最小化成本
