线程并不比无线程版本快多少

发布于 2024-12-10 09:46:14 字数 2687 浏览 0 评论 0原文

我知道还有其他类似的问题,但我是初学者,大多数代码和问题都非常复杂。这就是为什么我让它尽可能简单。我有 R 背景,但最近我想了解更多有关 Java 线程的知识。我浏览了有关该主题的几个教程,其中大部分都归结为我在下面发布的代码。请注意,代码没有做太多事情,而且我让它效率很低,因此线程将运行几秒钟。 需要注意的主要事情是,在我的机器上,线程运行速度并不比无线程运行快多少。如果 run 方法中的 for 循环值较低,有时甚至会更慢。这可能是因为我的硬件很糟糕(只有两个核心),并且随着核心的增加,线程会比非并行版本运行得更快。我不知道。但最让我困惑的是,当程序在两次运行(并行和非并行)中运行时,当我查看系统监视器时,两个核心都被使用,但在并行版本中,它们以接近 100% 的速度运行,而在非并行版本中,两个核心都以接近 100% 的速度运行。 50 - 60%。考虑到两者同时完成,并行版本的效率要低得多,因为它使用更多的计算机能力来完成相同的工作,甚至更快。 简而言之。我做错了什么?我认为我编写的程序与 Java 教程中的程序没有太大不同。我发布了下面的链接。我用sun版本的java运行linux ubuntu。

http://www.java2s.com/Tutorial/Java/0160__Thread/0020__Create -Thread.htm

import java.util.ArrayList;

public class Main { 
    public static void main(String[] args) {
        ArrayList<PermutateWord> words = new ArrayList<PermutateWord>();
        System.out.println(Runtime.getRuntime().availableProcessors());
        for(int i = 0; i < Runtime.getRuntime().availableProcessors();i++){
            words.add(new PermutateWord("Christoph"));
        }
        System.out.println("Run as thread");
        long d = System.currentTimeMillis();
        for (PermutateWord w : words) {
            w.start();
        }
        for (PermutateWord w : words) {
            try {
                w.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        for (PermutateWord w : words) {
            System.out.println(w.getWord());
        }
        System.out.println(((double)(System.currentTimeMillis()-d))/1000+"\n");
        System.out.println("No thread");
        d = System.currentTimeMillis();
        for (PermutateWord w : words) {
            w.run();
        }
        for (PermutateWord w : words) {
            System.out.println(w.getWord());
        }
        System.out.println(((double)(System.currentTimeMillis()-d))/1000+"\n");
    }
}
class PermutateWord extends Thread {    
    private String word;
    public PermutateWord (String word){
        this.word = word;
    }
    public void run() {
        java.util.Random rand = new java.util.Random();
        for(int i = 0; i <8000000;i++){
            word = swap(word,rand.nextInt(word.length()), rand.nextInt(word.length()));
        }
    }
    private String swap(String word2, int r1, int r2) {
        char[] wordArray = word2.toCharArray();
        char c = wordArray[r1];
        wordArray[r1] = wordArray[r2];
        wordArray[r2] = c;
        return new String(wordArray);
    }
    public String getWord(){
        return word;
    }
}

预先感

谢克里斯托夫

I know there are other questions like that but I'm a beginner and most of the code and questions were quite complicated. Thats why I keep it as simple as possible. I come from an R background but recently I wanted to learn more about Java threads. I run through several tutorial on the topic and most of it boils down to the code I posted below. Note the code is not doing much and I made it quite inefficient so the threads would run a few seconds.
The main thing to notice is that on my machine the threads run not much faster than the none threaded run. With low values in the for loop in the run method even sometimes slower. It could be because of my crappy hardware (only two cores), and that with more cores one would see the threads go faster than the non parallel version. I don't know. But what puzzles me most is that when I look at the System monitor while the program is running in both runs (parallel and non parallel) both cores are used but in the parallel version they run at nearly 100 % and in non parallel both run at 50 - 60 %. Considering that both finish at the same time the parallel version is a lot more inefficient because it uses more computer power for doing the same job not even faster.
To put it in the nutshell. What am I doing wrong? I thought I wrote the the program not much different than in the Java tutorial. I posted the link below. I run linux ubuntu with the sun version of java.

http://www.java2s.com/Tutorial/Java/0160__Thread/0020__Create-Thread.htm

import java.util.ArrayList;

public class Main { 
    public static void main(String[] args) {
        ArrayList<PermutateWord> words = new ArrayList<PermutateWord>();
        System.out.println(Runtime.getRuntime().availableProcessors());
        for(int i = 0; i < Runtime.getRuntime().availableProcessors();i++){
            words.add(new PermutateWord("Christoph"));
        }
        System.out.println("Run as thread");
        long d = System.currentTimeMillis();
        for (PermutateWord w : words) {
            w.start();
        }
        for (PermutateWord w : words) {
            try {
                w.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        for (PermutateWord w : words) {
            System.out.println(w.getWord());
        }
        System.out.println(((double)(System.currentTimeMillis()-d))/1000+"\n");
        System.out.println("No thread");
        d = System.currentTimeMillis();
        for (PermutateWord w : words) {
            w.run();
        }
        for (PermutateWord w : words) {
            System.out.println(w.getWord());
        }
        System.out.println(((double)(System.currentTimeMillis()-d))/1000+"\n");
    }
}
class PermutateWord extends Thread {    
    private String word;
    public PermutateWord (String word){
        this.word = word;
    }
    public void run() {
        java.util.Random rand = new java.util.Random();
        for(int i = 0; i <8000000;i++){
            word = swap(word,rand.nextInt(word.length()), rand.nextInt(word.length()));
        }
    }
    private String swap(String word2, int r1, int r2) {
        char[] wordArray = word2.toCharArray();
        char c = wordArray[r1];
        wordArray[r1] = wordArray[r2];
        wordArray[r2] = c;
        return new String(wordArray);
    }
    public String getWord(){
        return word;
    }
}

Thanks in advance

Christoph

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

烈酒灼喉 2024-12-17 09:46:14

大多数时间都花在分配和解除分配临时字符串上,这些字符串必须同步。可以并行完成的工作是微不足道的,多线程不会给你带来太多好处。

Math.random() 也必须同步。为每个线程创建本地 java.util.Random 将会获得更好的结果。

java.util.Random rand = new java.util.Random();

public void run() {
    for(int i = 0; i <8000000;i++){
        word = swap(word,rand.nextInt(word.length()), rand.nextInt(word.length()));
    }
}

但是,您应该真正专注于优化 swap 函数。我不确定它是否符合您的要求,但我确信它的效率非常低。 + 是对 String 进行昂贵的操作。对于每个 + JVM 都必须分配新的 String,这很慢并且不能很好地处理多线程。如果您只想交换两个字符,请考虑使用 char[] 而不是 String。它应该更容易、更快。

编辑:

private String swap(String word2, int r1, int r2) {
    char[] wordArray = word2.toCharArray();
    char c = wordArray[r1];
    wordArray[r1] = wordArray[r2];
    wordArray[r2] = c;
    return new String(wordArray);
}

这好多了。但是,您仍然进行 2 次分配。 toCharArray()new String 都分配内存。因为程序的其余部分非常简单,所以这两个分配占用了 90% 的执行时间。

Most of the time is spend allocating and dealocating temporary strings, which has to be synchronized. The work that can be done in parallel is trivial and multiple threads won't give you much gain.

Math.random() also has to be synchronized. You will have better results creating local java.util.Random for each thread.

java.util.Random rand = new java.util.Random();

public void run() {
    for(int i = 0; i <8000000;i++){
        word = swap(word,rand.nextInt(word.length()), rand.nextInt(word.length()));
    }
}

But, you should really focus on optimizing swap function. I'm not sure, if it does what you want, but I'm sure it's very inefficient. + is expensive operation on Strings. For every + JVM has to allocate new String which is slow and doesn't work well with multiple threads. If you just want to swap two characters, consider using char[] instead of String. It should be much easier and much faster.

edit:

private String swap(String word2, int r1, int r2) {
    char[] wordArray = word2.toCharArray();
    char c = wordArray[r1];
    wordArray[r1] = wordArray[r2];
    wordArray[r2] = c;
    return new String(wordArray);
}

This is much better. However, you are still doing 2 allocations. toCharArray() and new String both allocate memory. Because rest of your program is very simple, those two allocations take 90% of your execution time.

余生一个溪 2024-12-17 09:46:14

我通过将 Thread.sleep(1000) 放入 join 循环中获得了很多好处。
根据经验,java.util.Random.nextFloat() 只给我买了 10%。

即便如此,这两个部分在 8 核机器上的运行时间为 16 秒,这表明它是
由于上述同步而进行序列化。但好在,悲伤,没有
睡眠时它的运行速度慢了 10 倍。

I got a lot of mileage out of putting a Thread.sleep(1000) in the join loop.
Empirically, java.util.Random.nextFloat() only bought me 10%.

Even then, both parts ran in 16 seconds on an 8-core machine, suggesting it's
serializing due to the synchronizations mentioned above. But good, grief, without
the sleep it was running 10x slower.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文