![](/img/trans.png)
[英]does thread.sleep in quartz have to match the time for my schedule?
[英]Does Thread.sleep have no effect in Stream processing?
以下程序來自 Jeanne Boyarsky 和 Scott Selikoff 的 OCP 學習指南:
import java.util.*;
class WhaleDataCalculator {
public int processRecord(int input) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// Handle interrupted exception
}
return input + 1;
}
public void processAllData(List<Integer> data) {
data.stream().map(a -> processRecord(a)).count();
}
public static void main(String[] args) {
WhaleDataCalculator calculator = new WhaleDataCalculator();
// Define the data
List<Integer> data = new ArrayList<Integer>();
for (int i = 0; i < 4000; i++)
data.add(i);
// Process the data
long start = System.currentTimeMillis();
calculator.processAllData(data);
double time = (System.currentTimeMillis() - start) / 1000.0;
// Report results
System.out.println("\nTasks completed in: " + time + " seconds");
}
}
作者聲稱
假設有 4,000 條記錄,每條記錄需要 10 毫秒來處理,通過使用串行 stream(),結果將需要大約 40 秒才能完成此任務。
但是,當我在我的系統中運行它時,每次運行需要 0.006 秒到 0.009 秒。
差異在哪里?
這是因為使用了count
,它在后來的 Java 版本中執行了一個技巧。
由於您只對元素的數量感興趣,因此count
將嘗試直接從源中獲取大小,並將跳過大多數其他操作。 這是可能的,因為您只是在做一個map
而不是,例如,一個filter
,所以元素的數量不會改變。
如果添加peek(System.out::println)
,您也不會看到 output。
如果您調用forEach
而不是count
,運行代碼可能需要 40 秒。
.map(a -> processRecord(a))
的調用根本沒有運行,原因是你運行這個程序的 JDK 版本超過 1.8。
為了便於理解,我們舉這個例子:
long number = Stream.of("x", "x", "x").map(e -> {
System.out.println("Hello");
return e;
}).count();
System.out.println(number);
嘗試使用 JDK 1.8 運行它,然后使用 JDK 11 運行它。
在java 8中, count()作為一個終端操作,所有的中間操作(這里是map方法)都會被執行,map操作會被執行並打印hello消息。 你會得到這個 output:
Hello
Hello
Hello
3
在大於1.8的Java版本中,這里以11為例, Java可以直接確定stream的元素個數,如果沒有中間操作可以改變stream的元素個數(例子:filter()),沒有會執行中間方法,只執行count方法,所以你不會看到任何hello消息,但是會計算這個stream的元素個數,你可以使用它。 您的 output 將是這樣的:
3
如果你想在 Java 大於 1.8 的版本中看到 hello 消息,你應該在你的 stream 管道中添加一個中間操作,它可以改變 stream 的元素數量,讓我們將過濾器方法添加到管道中並查看 output on java 11:
long number = Stream.of("x", "x", "x").map(e -> {
System.out.println("Hello");
return e;
}).filter(element-> element.equals("x")).count();
System.out.println(number);
這里是 output:
Hello
Hello
Hello
3
由於 Java 9 操作count()
已經優化,因此如果在 stream 的初始化期間(當管道的各個階段被鏈接時)結果表明沒有可以更改 stream 源中元素數量的操作允許評估它包含的元素數量,然后count()
不會觸發管道的執行,而是詢問源“你有多少這些人?” 並立即返回值。
這是文檔中的引述:
API 備注:
如果實現能夠直接從 stream 源計算計數,則它可以選擇不執行 stream 管道(順序或並行)。 在這種情況下,不會遍歷任何源元素,也不會評估任何中間操作。 具有副作用的行為參數,除了調試等無害情況外,強烈建議不要使用,可能會受到影響。例如,考慮以下 stream:
List<String> l = Arrays.asList("A", "B", "C", "D"); long count = l.stream().peek(System.out::println).count();
stream 源
List
涵蓋的元素數量是已知的,中間操作peek
不會從 stream 中注入或移除元素(對於flatMap
或filter
操作可能就是這種情況)。 因此count
是List
的大小,不需要執行管道,作為副作用,打印出列表元素。
順便說一下,除了這個測試背后的技巧之外,這個案例不需要使用 Stream API。因為count()
返回的值被忽略了,所有需要做的就是對每個元素產生副作用列表,然后可以使用Iterable.forEach()
代替:
public void processAllData(List<Integer> data) {
data.forEach(a -> processRecord(a));
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.