我知道还有其他问题,但我是初学者,大多数代码和问题都很复杂。这就是为什么我保持尽可能简单。我来自R背景,但最近我想了解更多有关Java线程的知识。我经历了几个关于这个主题的教程,其中大部分归结为我在下面发布的代码。请注意,代码没有做太多,我的效率非常低,因此线程会运行几秒钟。 需要注意的主要事情是,在我的机器上,线程的运行速度并不比无线程运行快。在run方法中for循环中的值较低,有时甚至更慢。这可能是因为我的硬件很糟糕(只有两个核心),而且有了更多内核,人们会看到线程比非并行版本更快。我不知道。但最令我困惑的是,当程序在两次运行(并行和非并行)运行时查看系统监视器时,使用两个核心,但在并行版本中,它们以接近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;
}
}
提前致谢
了Christoph
答案 0 :(得分:5)
大部分时间都是花费分配和处理临时字符串,必须同步。可以并行完成的工作是微不足道的,多线程不会给你带来太多好处。
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%的执行时间。
答案 1 :(得分:0)
我在连接循环中放入Thread.sleep(1000)后得到了很多好处。 根据经验,java.util.Random.nextFloat()只给我买了10%。
即便如此,两部分机器在一台8芯机器上运行16秒,这表明它是 由于上面提到的同步而序列化。但好,悲伤,没有 它的睡眠速度慢了10倍。