簡體   English   中英

為什么我的 ExecutorService 實現比單線程實現更差?

[英]Why is my ExecutorService implementation performing worse than single threaded implementation?

我一直在嘗試多線程康威的生命游戲程序。 我天真的解決方案的一部分是大致做我在下面所做的事情。 然而,即使這個基本實現的性能也比單線程解決方案差得多,這突出了我不理解某些東西的事實。

我還應該說,如果不清楚,我需要在 while 循環的每次迭代結束時“加入”線程,這就是我使用 Callable 的原因 - 這樣我就可以獲得並迭代 Futures .

任何反饋,意見建議將非常受歡迎。

package lewi0231.testOne;

import java.util.ArrayList;
import java.util.concurrent.*;

public class LongRunningTask {
    int count;
    boolean[][] board = new boolean[200][200];
    ExecutorService threadPool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

    public LongRunningTask(int count) {
        this.count = count;
    }

    public void processTask() {
        int i = 0;
        ArrayList<Future<Integer>> futures = new ArrayList<>();

        while(i < count){
            for (int k = 1; k < board.length; k++){
                futures.add(threadPool.submit(new Callable<Integer>() {
                    @Override
                    public Integer call() throws Exception {
                        for (int l = 1; l < board[0].length; l++){
                                //Do Something Here
                        }
                        return 1;
                    }
                }));
            }

            for (Future<Integer> f : futures){
                try {
                    f.get();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (ExecutionException e) {
                    e.printStackTrace();
                }
            }

            i++;
        }
    }
}

class HypotheticalGUI{
    public static void main(String[] args) {
        LongRunningTask task = new LongRunningTask(100);

        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                task.processTask();
            }
        });
        thread.start();
    }
}

當線程(運行)的數量明顯超過可用處理器的數量時,可能會發生過多的上下文切換。 這意味着創建線程的開銷加上在線程之間切換的開銷會影響性能。

上下文切換尤其具有破壞性,因為每當處理器從一個線程切換到另一個線程時,它必須刷新其緩存並重新加載新線程的上下文。 這種意義上的上下文是指線程的堆棧、寄存器和程序計數器的內容。

更好的方法是嘗試將可用處理器的數量與創建的線程數量相匹配。 見下文:

import java.util.ArrayList;
import java.util.concurrent.*;

public class LongRunningTask {
    int count;
    boolean[][] board = new boolean[200][200];
    int numProcessors = Runtime.getRuntime().availableProcessors() - 1;
    ExecutorService threadPool = Executors.newFixedThreadPool(numProcessors);

    public LongRunningTask(int count) {
        this.count = count;
    }

    public void processTask() {
        int i = 0;
        ArrayList<Future<Integer>> futures = new ArrayList<>();
        int startIndex = 1;
        int partitionSize = board.length / numProcessors;

        while(i < count){
            while (startIndex < board.length) {
                futures.add(threadPool.submit(new MyCallable(startIndex, partitionSize, board)));
                startIndex += partitionSize;
            }

            for (Future<Integer> f : futures){
                try {
                    f.get();
                } catch (InterruptedException | ExecutionException e) {
                    e.printStackTrace();
                }
            }

            i++;
        }
    }
}

class MyCallable implements Callable<Integer> {
    private final int startIndex;
    private final int partitionSize;
    private final boolean[][] board;

    public MyCallable(int startIndex, int partitionSize, boolean[][] board){
        this.startIndex = startIndex;
        this.partitionSize = partitionSize;
        this.board = board;
    }

    @Override
    public Integer call() throws Exception {
        int endIndex = Math.min(startIndex + partitionSize, board.length - 1);
        for (int k = startIndex; k < endIndex; k++){
            for (int l = 1; l < board[0].length; l++){
                //Do Something Here
            }
        }
        return 1;
    }
}

class HypotheticalGUI{
    public static void main(String[] args) {
        LongRunningTask task = new LongRunningTask(100);

        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                task.processTask();
            }
        });
        thread.start();
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM