Java 线程不比无线程版本快很多

Java 线程不比无线程版本快很多,java,multithreading,Java,Multithreading,我知道还有其他类似的问题,但我是个初学者,大多数代码和问题都相当复杂。这就是为什么我要让它尽可能简单。我有R的背景,但最近我想学习更多关于Java线程的知识。我浏览了几个关于这个主题的教程,其中大部分都归结为我在下面发布的代码。注意,代码做的不多,我使它效率很低,因此线程将运行几秒钟。 需要注意的主要问题是,在我的机器上,线程的运行速度并不比无线程运行快多少。在for循环中使用较低的值时,run方法有时甚至更慢。这可能是因为我糟糕的硬件只有两个内核,而且如果有更多的内核,线程的速度会比非并行版本

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

提前谢谢


Christoph

大多数时间是分配和取消分配临时字符串,这些字符串必须同步。可以并行完成的工作很琐碎,多线程不会给您带来太多好处

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()));
    }
}

这样好多了。但是,您仍在进行2次分配。ToCharray和new String都分配内存。由于程序的其余部分非常简单,这两个分配占用了90%的执行时间。

大部分时间用于分配和取消分配临时字符串,而这些字符串必须同步。可以并行完成的工作很琐碎,多线程不会给您带来太多好处

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()));
    }
}

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

将Thread.sleep1000放入联接循环中,我获得了很多好处。 根据经验,java.util.Random.nextFloat只为我买了10%

即便如此,这两个部件在一台8核机器上运行的时间都是16秒,这表明它是 由于上述同步而序列化。但是好,悲伤,没有痛苦
sleep it的运行速度慢了10倍。

我在加入循环中加入一个Thread.sleep1000,这让我跑了很多里程。 根据经验,java.util.Random.nextFloat只为我买了10%

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

就像@akappa说你在不同的线程中做相同的事情。这就像说你同时运行应用程序的多个实例。他们没有共享任务,但每个人都在执行sametask。java2s也没有最好的示例。请注意,在我的双核windows机器上,运行5次时,多线程平均需要11.966秒,单线程平均需要18.3秒。@Shahzeb请参阅我对akappa答案的评论-这种并行方法不一定有用,但应该会带来一些性能提升。@DanielBuckmaster:您对我的答案的回答假设了它的非线程版本,这不包括在问题中。也许OP也应该发布它,但在我看来,这是一种可笑的并行化方式。@Bashkar。我可以确认你的结果,10.2对14.0秒。我的双核真是糟透了!就像@akappa说你在不同的线程中做相同的事情,就像说你在同时运行应用程序的多个实例。他们没有共享任务,但每个人都在执行sametask。java2s也没有最好的示例。请注意,在我的双核windows机器上,运行5次时,多线程平均需要11.966秒,单线程平均需要18.3秒。@Shahzeb请参阅我对akappa答案的评论-这种并行方法不一定有用,但应该会带来一些性能提升。@DanielBuckmaster:您对我的答案的回答假设了它的非线程版本,这不包括在问题中。也许OP也应该发布它,但在我看来,这是一种可笑的并行化方式。@Bashkar。我可以骗你
确定你的结果,10.2对14.0秒。我的双核真是糟透了!对于Java专业人士来说,这可能听起来很愚蠢,但我该怎么做呢?谢谢!这两种建议都大大提高了性能,但对多线程没有任何影响。正如你在回答中所说的。你能给我解释一下为什么可以并行完成的工作很琐碎,而且多线程不会给我带来太多好处吗。读了所有的帖子,我对它的理解似乎在很久以前的某个地方迷失了方向。这对我来说非常有效。在PermutateWord中,您应该有一个本地随机私有随机=新随机;然后使用random.nextFloat而不是Math.random这对Java专业人士来说可能听起来很傻,但是我该怎么做呢?谢谢!这两种建议都大大提高了性能,但对多线程没有任何影响。正如你在回答中所说的。你能给我解释一下为什么可以并行完成的工作很琐碎,而且多线程不会给我带来太多好处吗。读了所有的帖子,我对它的理解似乎在很久以前的某个地方迷失了方向。这对我来说非常有效。在PermutateWord中,您应该有一个本地随机私有随机=新随机;然后使用random.nextFloat代替Math.random
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);
}