日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

java 并行 执行进度_关于java:Java8流的顺序执行和并行执行产生不同的结果?

發布時間:2025/3/19 java 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java 并行 执行进度_关于java:Java8流的顺序执行和并行执行产生不同的结果? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

在Java8中運行以下流示例:

System.out.println(Stream

.of("a","b","c","d","e","f")

.reduce("", (s1, s2) -> s1 +"/" + s2)

);

收益率:

/a/b/c/d/e/f

當然-這并不奇怪。

由于http://docs.oracle.com/javase/8/docs/api/index.html?overview-summary.html,流是順序執行還是并行執行并不重要:

Except for operations identified as explicitly nondeterministic, such as findAny(), whether a stream executes sequentially or in parallel should not change the result of the computation.

AFAIK reduce()是確定性的,而(s1, s2) -> s1 +"/" + s2是關聯的,因此添加parallel()應該會產生相同的結果:

System.out.println(Stream

.of("a","b","c","d","e","f")

.parallel()

.reduce("", (s1, s2) -> s1 +"/" + s2)

);

但是我的機器上的結果是:

/a//b//c//d//e//f

怎么了

順便說一句:使用(首選).collect(Collectors.joining("/"))而不是reduce(...)對于順序執行和并行執行會產生相同的結果a/b/c/d/e/f。

JVM詳細信息:

java.specification.version: 1.8

java.version: 1.8.0_31

java.vm.version: 25.31-b07

java.runtime.version: 1.8.0_31-b13

實際上,似乎特別聲明了,如果您的BinaryOperator是關聯的,那么它應該適用于并行流。

正如其他答復者所指出的那樣,除了不遵循減少的規則外,還有一種更簡單的方法可以完成您的工作:stream.collect(joining(""))

從reduce的文檔中:

The identity value must be an identity for the accumulator function. This means that for all t, accumulator.apply(identity, t) is equal to t.

在您的情況下,這是不正確的-"和" a"創建為" / a"。

我已經提取了累加器功能并添加了打印輸出以顯示發生了什么:

BinaryOperator accumulator = (s1, s2) -> {

System.out.println("joining "" + s1 +"" and "" + s2 +""");

return s1 +"/" + s2;

};

System.out.println(Stream

.of("a","b","c","d","e","f")

.parallel()

.reduce("", accumulator)

);

這是示例輸出(運行之間有所不同):

joining"" and"d"

joining"" and"f"

joining"" and"b"

joining"" and"a"

joining"" and"c"

joining"" and"e"

joining"/b" and"/c"

joining"/e" and"/f"

joining"/a" and"/b//c"

joining"/d" and"/e//f"

joining"/a//b//c" and"/d//e//f"

/a//b//c//d//e//f

您可以在函數中添加if語句以分別處理空字符串:

System.out.println(Stream

.of("a","b","c","d","e","f")

.parallel()

.reduce((s1, s2) -> s1.isEmpty()? s2 : s1 +"/" + s2)

);

正如Marko Topolnik所注意到的,由于累加器不一定是可交換函數,因此不需要檢查s2。

太好了!因此,使用不使用身份的reduce也可以解決問題.reduce((s1, s2) -> s1 +"" + s2)。

最好使用條件表達式,恕我直言:(s1, s2) -> s1.isEmpty()? s2 : s2.isEmpty()? s1 : s1 +"" + s2

另外,由于累加器功能不需要交換,因此您實際上不需要檢查s2是否為空。因此,(s1, s2) -> s1.isEmpty()? s2 : s1+""+s2就足夠了。

或者他可以使用stream.collect(Collectors.joining("","",""))

@mk。這不是真的。第一步可以在3個線程中并行完成,分別創建a / b,c / d和e / f。然后,我們可以將前兩個加入創建a / b / c / d,然后將其與e / f加入創建a / b / c / d / e / f。我在考慮身份是否會給我們帶來任何好處,但是我找不到任何很好的解釋-將功能與身份元素一起使用是多余的操作,它只會產生第二個元素。

因此,最大的問題是,為什么實現不能僅在內部將reduce(identity, accumulator)委托給reduce(accumulator).orElse(identity),因為" accumulator.apply(identity, t)等于t"的要求意味著在每個評估線程中執行whatever=accumulator.apply(identity, whatever)是胡說八道。

@Holger也許僅僅是因為它與FP純粹主義者不合時宜:)

正是這一點:a + 0 != a。我沒有閱讀reduce文檔中的注釋。 +1

要添加其他答案,

您可能要使用Mutable減少,文檔指定執行類似

String concatenated = strings.reduce("", String::concat)

會給出不良的性能結果。

We would get the desired result, and it would even work in parallel.

However, we might not be happy about the performance! Such an

implementation would do a great deal of string copying, and the run

time would be O(n^2) in the number of characters. A more performant

approach would be to accumulate the results into a StringBuilder,

which is a mutable container for accumulating strings. We can use the

same technique to parallelize mutable reduction as we do with ordinary

reduction.

因此,您應該改用StringBuilder。

對于剛開始使用lambda和流的人來說,花了很長時間才到達" AHA"時刻,直到我真正了解這里發生了什么。我會對此重新措辭,以使像我這樣的新手流變得更輕松(至少我希望它真的得到了答復)。

所有這些都在reduce文檔中指出:

標識值必須是累加器功能的標識。這意味著對于所有t,accumulator.apply(identity,t)等于t。

我們可以輕松證明代碼的方式,關聯性被破壞:

static private void isAssociative() {

BinaryOperator operator = (s1, s2) -> s1 +"/" + s2;

String result = operator.apply("","a");

System.out.println(result);

System.out.println(result.equals("a"));

}

一個空字符串與另一個字符串串聯,應該真正產生第二個字符串。這不會發生,因此累加器(BinaryOperator)不具有關聯性,因此在并行調用的情況下,reduce方法不能保證相同的結果。

操作員的關聯性沒有被破壞,唯一的問題是身份值。參見docs.oracle.com/javase/8/docs/api/java/util/stream/

與50位技術專家面對面20年技術見證,附贈技術全景圖

總結

以上是生活随笔為你收集整理的java 并行 执行进度_关于java:Java8流的顺序执行和并行执行产生不同的结果?的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。