简体   繁体   English

线程工作结果出乎意料 - java

[英]threading work results are unexpected - java

i am new at multi threading.我是多线程新手。 i am working on a program to read a file with many records (3 million integer numbers) into some linked list and then some threads work on each list and calculate the sum of the list, finding the maximum and minimum.我正在开发一个程序,将一个包含许多记录(300 万个整数)的文件读入某个链接列表,然后一些线程处理每个列表并计算列表的总和,找到最大值和最小值。 then the main thread compares the child thread results and display the final results.然后主线程比较子线程结果并显示最终结果。

program work with this command:程序使用此命令:

compute -f file_path -t threads_Number计算 -f 文件路径 -t 线程数

Now the problem is when i run the program with one thread it takes less time than some threads.现在的问题是,当我用一个线程运行程序时,它比某些线程花费的时间少。

my CPU is core i7.我的CPU是酷睿i7。

this is some time results:这是一段时间的结果:

(Threads : duration) --> (1 : 16) , (2,3 : 32) , (4,5,6,7 : 47) , (8,9 : 31) ... (17,18,19,20 : 16) (线程:持续时间)--> (1 : 16) , (2,3 : 32) , (4,5,6,7 : 47) , (8,9 : 31) ... (17,18,19 ,20 : 16)

the project have 2 projects:该项目有2个项目:

Worker class:工人阶级:

public class Worker implements Runnable {

    private List<Integer> records;
    private long[] res;
    private String name;

    Worker(String name, LinkedList<Integer> list, long[] res) {
        this.records = list;
        this.res = res;
        this.name = name;
    }

    @Override
    public void run() {

        long startTime = System.currentTimeMillis();
        long sum = 0;
        int max, min;

        if (records != null && records.size() > 0) {
            max = min = records.get(0);

            for (Integer num : records) {
                sum += num;
                if (num > max)
                    max = num;
                if (num < min)
                    min = num;
            }

            long endTime = System.currentTimeMillis();
            long duration = endTime - startTime;

            res[0] = sum;
            res[1] = max;
            res[2] = min;
            res[3] = duration;

            System.out.println(name + "\t->\ttime:\t" + duration + "\t, Records:\t" + records.size());
        }
    }
}

Main class:主要类:

public class Main {

    public static void main(String[] args) {
        //read command and get inputs:
        System.out.println("Welcome to my app : ");

        while (true) {

            Scanner scanner = new Scanner(System.in);
            String command = scanner.nextLine().trim();
            if (command.startsWith("compute")) {
                command = command.substring("compute".length() + 1);
                args = command.split(" ");
            } else {
                System.out.println("wrong command.. this app only support 'compute'");
                exit(1);
            }

            Map<String, String> map = new HashMap<>(); //-p processes , -f filepath
            for (int i = 0; i < args.length - 1; i += 2)
                map.put(args[i], args[i + 1]);

            File txtFile = new File(map.get("-f").trim());
            final int threadCount = Integer.parseInt(map.get("-t").trim());

            ArrayList<LinkedList<Integer>> lists = readFile(txtFile, threadCount);
            if (lists == null) {
                System.out.println("Error: can not found txt file..");
                exit(2);
            }

            long[][] results = new long[threadCount][4];
            Thread[] thread = new Thread[threadCount];

            for (int i = 0; i < threadCount; i++) {
                thread[i] = new Thread(new Worker("thread " + (i + 1) ,lists.get(i), results[i]));
                thread[i].start();
            }

            boolean isAlive = true;
            while (isAlive) {
                isAlive = false;
                for (int i = 0; i < threadCount; i++)
                    isAlive |= thread[i].isAlive();
            }

            long[] res = null;
            for (long[] result : results) {
                if (res != null) {
                    res[0] += result[0];
                    if (res[1] < result[1])
                        res[1] = result[1];
                    if (res[2] > result[2])
                        res[2] = result[2];
                    if (res[3] < result[3])
                        res[3] = result[3];
                } else {
                    res = result;
                }
            }

            if (res != null) {
                System.out.println("sum : " + res[0]);
                System.out.println("max : " + res[1]);
                System.out.println("min : " + res[2]);
                System.out.println("duration : " + res[3]);
            }

        }
    }

    private static ArrayList<LinkedList<Integer>> readFile(File txtFile, int procCount) {
        if(!txtFile.exists() || txtFile.isDirectory())
            return null;

        ArrayList<LinkedList<Integer>> arrayList = new ArrayList<>();

        for(int i = 0; i < procCount; i++)
            arrayList.add(new LinkedList<>());

        try {
            int index = 0;
            BufferedReader bufferedReader = new BufferedReader(new FileReader(txtFile));
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                arrayList.get(index).add(Integer.parseInt(line));
                index++;
                if(index == procCount)
                    index = 0;
            }

            return arrayList;
        }   catch (IOException e) {
            e.printStackTrace();
            return null;
        }

    }
}

Why do you not use Executors ? 为什么不使用执行器

With the argument Integer.parseInt(map.get("-t").trim()) you create a Pool of Threads . 使用参数 Integer.parseInt(map.get(“-t”)。trim())创建一个线程池 And isAlive is not longer required. 并且不再需要isAlive。 And the results the concept of Future . 得出Future的概念。

Threads Pool 线程池

Future 未来

Executors - Threads Control 执行器-线程控制

Examples 例子

I think in order to learn multi-threading it is important to know about the Amdahl's law. 我认为,为了学习多线程,了解阿姆达尔定律很重要。 Amdahl's law can be used to calculate how much a computation can be sped up by running part of it in parallel. 阿姆达尔定律可用于计算通过并行运行一部分计算可加速的计算量。 I don't want to go too much into the technical detail so you can read about it on Wikipedia: https://en.wikipedia.org/wiki/Amdahl%27s_law 我不想过多地讨论技术细节,因此您可以在Wikipedia上阅读: https//en.wikipedia.org/wiki/Amdahl%27s_law

Amdahl's law basically says the speedup of concurrent computing is not linear to the number of your threads, which are dependent on the number of cores in your processor (Unless your code does networking, IO, etc.). 阿姆达尔定律从根本上说,并发计算的速度与线程数不是线性关系,线程数取决于处理器中的内核数(除非您的代码进行网络,IO等)。 Hence you can not expect your program to double it speeds when you double your number of threads. 因此,当您将线程数量加倍时,就不能指望程序将其速度提高一倍。

Moreover the class Thread, like any other class in java would take a lot of overhead to be created and will take a lot of resource. 而且,Thread类与Java中的其他任何类一样,将花费大量创建开销,并且会占用大量资源。 Therefore creating more threads without efficiently balancing the input for only arithmetic operations (which are already very optimized by the JVM) will make the speed of your program unpredictable or even slower. 因此,创建更多线程而没有有效地仅对算术运算(JVM已经对其进行了非常优化)的输入进行有效平衡时,将使程序的速度无法预测甚至变慢。

There are lots more problems which are needed to considered. 还有更多的问题需要考虑。 A little suggest is using the class ExecutorService of Java to manage your threads. 一个小建议是使用Java的ExecutorService类来管理您的线程。 Happy coding. 快乐的编码。

Your 'out of the ordinary' results most probably have to do with optimizations done by the JIT compiler 您“与众不同”的结果很可能与JIT编译器完成的优化有关

Your code is doing 'kind of a benchmark' here, with a configurable number of threads. 您的代码在这里正在执行“某种基准测试”,具有可配置的线程数。 For such benchmarks it's recommended to use the JMH framework . 对于此类基准,建议使用JMH框架

In case you are just learning multi-threading, I recommend you avoid measuring the performance of you code. 如果您只是在学习多线程,建议您不要评估代码的性能。 There are lots of things to be considered when doing benchmarks, and failing to do them right will result in unexpected result, such as the one you are seeing now. 进行基准测试时,有很多事情要考虑,如果做不正确,将会导致意外的结果,例如您现在看到的结果。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM