<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                ## 復雜性和代價 假設你正在做披薩,我們把從整個流程的當前步驟到下一個步驟所需的工作量,在這里一一表示為枚舉變量的一部分: ```java // concurrent/Pizza.java import java.util.function.*; import onjava.Nap; public class Pizza{ public enum Step{ DOUGH(4), ROLLED(1), SAUCED(1), CHEESED(2), TOPPED(5), BAKED(2), SLICED(1), BOXED(0); int effort;// Needed to get to the next step Step(int effort){ this.effort = effort; } Step forward(){ if (equals(BOXED)) return BOXED; new Nap(effort * 0.1); return values()[ordinal() + 1]; } } private Step step = Step.DOUGH; private final int id; public Pizza(int id){ this.id = id; } public Pizza next(){ step = step.forward(); System.out.println("Pizza " + id + ": " + step); return this; } public Pizza next(Step previousStep){ if (!step.equals(previousStep)) throw new IllegalStateException("Expected " + previousStep + " but found " + step); return next(); } public Pizza roll(){ return next(Step.DOUGH); } public Pizza sauce(){ return next(Step.ROLLED); } public Pizza cheese(){ return next(Step.SAUCED); } public Pizza toppings(){ return next(Step.CHEESED); } public Pizza bake(){ return next(Step.TOPPED); } public Pizza slice(){ return next(Step.BAKED); } public Pizza box(){ return next(Step.SLICED); } public boolean complete(){ return step.equals(Step.BOXED); } @Override public String toString(){ return "Pizza" + id + ": " + (step.equals(Step.BOXED) ? "complete" : step); } } ``` 這只算得上是一個平凡的狀態機,就像**Machina**類一樣。 制作一個披薩,當披薩餅最終被放在盒子中時,就算完成最終任務了。 如果一個人在做一個披薩餅,那么所有步驟都是線性進行的,即一個接一個地進行: ```java // concurrent/OnePizza.java import onjava.Timer; public class OnePizza{ public static void main(String[] args){ Pizza za = new Pizza(0); System.out.println(Timer.duration(() -> { while (!za.complete()) za.next(); })); } } ``` 輸出結果: ``` Pizza 0: ROLLED Pizza 0: SAUCED Pizza 0: CHEESED Pizza 0: TOPPED Pizza 0: BAKED Pizza 0: SLICED Pizza 0: BOXED 1622 ``` 時間以毫秒為單位,加總所有步驟的工作量,會得出與我們的期望值相符的數字。 如果你以這種方式制作了五個披薩,那么你會認為它花費的時間是原來的五倍。 但是,如果這還不夠快怎么辦? 我們可以從嘗試并行流方法開始: ```java // concurrent/PizzaStreams.java // import java.util.*; import java.util.stream.*; import onjava.Timer; public class PizzaStreams{ static final int QUANTITY = 5; public static void main(String[] args){ Timer timer = new Timer(); IntStream.range(0, QUANTITY) .mapToObj(Pizza::new) .parallel()//[1] .forEach(za -> { while(!za.complete()) za.next(); }); System.out.println(timer.duration()); } } ``` 輸出結果: ``` Pizza 2: ROLLED Pizza 0: ROLLED Pizza 1: ROLLED Pizza 4: ROLLED Pizza 3:ROLLED Pizza 2:SAUCED Pizza 1:SAUCED Pizza 0:SAUCED Pizza 4:SAUCED Pizza 3:SAUCED Pizza 2:CHEESED Pizza 1:CHEESED Pizza 0:CHEESED Pizza 4:CHEESED Pizza 3:CHEESED Pizza 2:TOPPED Pizza 1:TOPPED Pizza 0:TOPPED Pizza 4:TOPPED Pizza 3:TOPPED Pizza 2:BAKED Pizza 1:BAKED Pizza 0:BAKED Pizza 4:BAKED Pizza 3:BAKED Pizza 2:SLICED Pizza 1:SLICED Pizza 0:SLICED Pizza 4:SLICED Pizza 3:SLICED Pizza 2:BOXED Pizza 1:BOXED Pizza 0:BOXED Pizza 4:BOXED Pizza 3:BOXED 1739 ``` 現在,我們制作五個披薩的時間與制作單個披薩的時間就差不多了。 嘗試刪除標記為[1]的行后,你會發現它花費的時間是原來的五倍。 你還可以嘗試將**QUANTITY**更改為4、8、10、16和17,看看會有什么不同,并猜猜看為什么會這樣。 **PizzaStreams** 類產生的每個并行流在它的`forEach()`內完成所有工作,如果我們將其各個步驟用映射的方式一步一步處理,情況會有所不同嗎? ```java // concurrent/PizzaParallelSteps.java import java.util.*; import java.util.stream.*; import onjava.Timer; public class PizzaParallelSteps{ static final int QUANTITY = 5; public static void main(String[] args){ Timer timer = new Timer(); IntStream.range(0, QUANTITY) .mapToObj(Pizza::new) .parallel() .map(Pizza::roll) .map(Pizza::sauce) .map(Pizza::cheese) .map(Pizza::toppings) .map(Pizza::bake) .map(Pizza::slice) .map(Pizza::box) .forEach(za -> System.out.println(za)); System.out.println(timer.duration()); } } ``` 輸出結果: ``` Pizza 2: ROLLED Pizza 0: ROLLED Pizza 1: ROLLED Pizza 4: ROLLED Pizza 3: ROLLED Pizza 1: SAUCED Pizza 0: SAUCED Pizza 2: SAUCED Pizza 3: SAUCED Pizza 4: SAUCED Pizza 1: CHEESED Pizza 0: CHEESED Pizza 2: CHEESED Pizza 3: CHEESED Pizza 4: CHEESED Pizza 0: TOPPED Pizza 2: TOPPED Pizza 1: TOPPED Pizza 3: TOPPED Pizza 4: TOPPED Pizza 1: BAKED Pizza 2: BAKED Pizza 0: BAKED Pizza 4: BAKED Pizza 3: BAKED Pizza 0: SLICED Pizza 2: SLICED Pizza 1: SLICED Pizza 3: SLICED Pizza 4: SLICED Pizza 1: BOXED Pizza1: complete Pizza 2: BOXED Pizza 0: BOXED Pizza2: complete Pizza0: complete Pizza 3: BOXED Pizza 4: BOXED Pizza4: complete Pizza3: complete 1738 ``` 答案是“否”,事后看來這并不奇怪,因為每個披薩都需要按順序執行步驟。因此,沒法通過分步執行操作來進一步提高速度,就像上文的 `PizzaParallelSteps.java` 里面展示的一樣。 我們可以使用 **CompletableFutures** 重寫這個例子: ```java // concurrent/CompletablePizza.java import java.util.*; import java.util.concurrent.*; import java.util.stream.*; import onjava.Timer; public class CompletablePizza{ static final int QUANTITY = 5; public static CompletableFuture<Pizza> makeCF(Pizza za){ return CompletableFuture .completedFuture(za) .thenApplyAsync(Pizza::roll) .thenApplyAsync(Pizza::sauce) .thenApplyAsync(Pizza::cheese) .thenApplyAsync(Pizza::toppings) .thenApplyAsync(Pizza::bake) .thenApplyAsync(Pizza::slice) .thenApplyAsync(Pizza::box); } public static void show(CompletableFuture<Pizza> cf){ try{ System.out.println(cf.get()); } catch (Exception e){ throw new RuntimeException(e); } } public static void main(String[] args){ Timer timer = new Timer(); List<CompletableFuture<Pizza>> pizzas = IntStream.range(0, QUANTITY) .mapToObj(Pizza::new) .map(CompletablePizza::makeCF) .collect(Collectors.toList()); System.out.println(timer.duration()); pizzas.forEach(CompletablePizza::show); System.out.println(timer.duration()); } } ``` 輸出結果: ``` 169 Pizza 0: ROLLED Pizza 1: ROLLED Pizza 2: ROLLED Pizza 4: ROLLED Pizza 3: ROLLED Pizza 1: SAUCED Pizza 0: SAUCED Pizza 2: SAUCED Pizza 4: SAUCED Pizza 3: SAUCED Pizza 0: CHEESED Pizza 4: CHEESED Pizza 1: CHEESED Pizza 2: CHEESED Pizza 3: CHEESED Pizza 0: TOPPED Pizza 4: TOPPED Pizza 1: TOPPED Pizza 2: TOPPED Pizza 3: TOPPED Pizza 0: BAKED Pizza 4: BAKED Pizza 1: BAKED Pizza 3: BAKED Pizza 2: BAKED Pizza 0: SLICED Pizza 4: SLICED Pizza 1: SLICED Pizza 3: SLICED Pizza 2: SLICED Pizza 4: BOXED Pizza 0: BOXED Pizza0: complete Pizza 1: BOXED Pizza1: complete Pizza 3: BOXED Pizza 2: BOXED Pizza2: complete Pizza3: complete Pizza4: complete 1797 ``` 并行流和 **CompletableFutures** 是 Java 并發工具箱中最先進發達的技術。 你應該始終首先選擇其中之一。 當一個問題很容易并行處理時,或者說,很容易把數據分解成相同的、易于處理的各個部分時,使用并行流方法處理最為合適(而如果你決定不借助它而由自己完成,你就必須擼起袖子,深入研究**Spliterator**的文檔)。 而當工作的各個部分內容各不相同時,使用 **CompletableFutures** 是最好的選擇。比起面向數據,**CompletableFutures** 更像是面向任務的。 對于披薩問題,結果似乎也沒有什么不同。實際上,并行流方法看起來更簡潔,僅出于這個原因,我認為并行流作為解決問題的首次嘗試方法更具吸引力。 由于制作披薩總需要一定的時間,無論你使用哪種并發方法,你能做到的最好情況,是在制作一個披薩的相同時間內制作n個披薩。 在這里當然很容易看出來,但是當你處理更復雜的問題時,你就可能忘記這一點。 通常,在項目開始時進行粗略的計算,就能很快弄清楚最大可能的并行吞吐量,這可以防止你因為采取無用的加快運行速度的舉措而忙得團團轉。 使用 **CompletableFutures** 或許可以輕易地帶來重大收益,但是在嘗試更進一步時需要倍加小心,因為額外增加的成本和工作量會非常容易遠遠超出你之前拼命擠出的那一點點收益。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看