线程排序比非线程排序慢

时间:2015-06-07 07:04:48

标签: java multithreading sorting java-threads

我正在尝试使用线程对文件进行排序。这是Sort.java:

此功能在线程

的帮助下排序
public static String[] threadedSort(File[] files) throws IOException {
      String sortedData[] = new String[0]; 
      int counter = 0; 
      boolean allThreadsTerminated = false;
      SortingThread[] threadList = new SortingThread[files.length];
      for (File file : files) {
          String[] data = getData(file);
          threadList[counter] = new SortingThread(data);
          threadList[counter].start();
          counter++;
      }
      while(!allThreadsTerminated) {
          allThreadsTerminated = true;
          for(counter=0; counter<files.length; counter++) {
              if(threadList[counter].getState() != Thread.State.TERMINATED) {
                  allThreadsTerminated = false;               
              }           
          }
      }
      for(counter=0; counter<files.length; counter++) {
          sortedData = MergeSort.merge(sortedData, threadList[counter].data);
      }
      return sortedData;
 }

此功能正常排序

  public static String[] sort(File[] files) throws IOException {
    String[] sortedData = new String[0];
    for (File file : files) {
      String[] data = getData(file);
      data = MergeSort.mergeSort(data);
      sortedData = MergeSort.merge(sortedData, data);
    }
    return sortedData;
  }

现在,当我使用两种方式排序时,正常排序比线程版本更快。它有什么理由呢?我错过了什么?

我的SortingThread是这样的:

public class SortingThread extends Thread {
    String[] data;
    SortingThread(String[] data) {
        this.data = data;
    }
    public void run() {
         data = MergeSort.mergeSort(data);        
    }  
}

当我通过将其性能与原始的非线程实现进行比较来分析我的线程实现时,我发现第二个更快。这种行为可能是什么原因?如果我们谈论相对性能改进,我们希望如果没有错误,线程实现会更快。

编辑:假设我有正确的功能MergeSort。但是在这里发布代码毫无用处。 getData()函数也只是从文件中获取输入。 我认为问题在于我将整个文件放在数组中。我想我应该为不同的线程提供不同的行:

private static String[] getData(File file) throws IOException {
    ArrayList<String> data = new ArrayList<String>();
    BufferedReader in = new BufferedReader(new FileReader(file));
    while (true) {
      String line = in.readLine();
      if (line == null) {
        break;
      }
      else {
        data.add(line);
      }
    }


    in.close();
    return data.toArray(new String[0]);
  }

4 个答案:

答案 0 :(得分:1)

首先,您如何衡量经过的时间?你在同一个程序中执行两个测试吗?如果是这样,请记住,在执行第一个测试时,mergesort可能会进行Hotspot编译。我建议你每次运行两次方法,测量第二次运行的时间

答案 1 :(得分:0)

你有多少CPU /核心?这段代码的一个问题是主线程在&#34;而(!allThreadsT​​erminated)&#34;循环,主动检查线程状态。如果你有一个CPU - 你在浪费它,而不是做实际的排序。

将while循环替换为:

 for(counter=0; counter<files.length; counter++) {
        threadList[counter].join();
 }

答案 2 :(得分:0)

您应该使用Stream和标准排序:

static String[] sort(File[] files, boolean parallel) {
    return (parallel ? Stream.of(files).parallel() : Stream.of(files))
        .flatMap(f -> {
            try {
                return Files.lines(f.toPath());
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        })
        .sorted()
        .toArray(String[]::new);
}

static String[] sort(File[] files) {
    return sort(files, false);
}

static String[] threadSort(File[] files) {
    return sort(files, true);
}

在我的环境中threadSort更快。

sort:
files=511 sorted lines=104419 elapse=4784ms
threadSort:
files=511 sorted lines=104419 elapse=3060ms

答案 3 :(得分:0)

您可以使用private void Form1_Load(object sender, EventArgs e) { Obj1 obj1 = new Obj1(); Obj1 obj11 = new Obj1(); Obj2 obj2 = new Obj2(); Obj2 obj22 = new Obj2(); obj1.param1 = "1"; obj1.param2 = "2"; obj2.param3 = "3"; obj1.obj2 = obj2; obj11.param1 = "1"; obj11.param2 = "2"; obj22.param3 = "3"; obj11.obj2 = obj22; bool res = Compare.PublicInstancePropertiesEqual(obj1, obj11, ("secure")); } } class Obj1 { public string param1 { get; set; } public string param2 { get; set; } public Obj2 obj2 { get; set; } } class Obj2 { public string param3 { get; set; } public decimal param4 { get; set; } } ,它将在指定数量的线程中运行您的所有任务,并且一旦所有线程完成执行,您将获得一个列表java.util.concurrent.ExecutorService对象,该对象将保存每个线程执行的结果。 Future对象列表的顺序与将Callable对象插入其列表的顺序相同。

首先,您需要拥有Future实现SortingThread接口,以便获得每个线程执行的结果。
每个Callable对象都必须实现Callable方法,其返回类型将是您的call()对象。

Future

接下来,您需要使用 public class SortingThread implements Callable<String[]> { String[] data; SortingThread(String[] data) { this.data = data; } @Override public String[] call() throws Exception { data = MergeSort.mergeSort(data); return data; } } 进行线程管理。

ExecutorSerivce

这样你可以避免使用WHILE循环,这已知会增加CPU利用率(从而降低速度),如果你有单核CPU,那么它可以达到100%的利用率,如果双核然后50% 此外,在处理多线程而不是开始和监视线程的结果时,使用public static String[] sortingExampleWithMultiThreads(File[] files) throws IOException { String sortedData[] = new String[0]; int counter = 0; boolean allThreadsTerminated = false; SortingThread[] threadList = new SortingThread[files.length]; ArrayList<Callable<String[]>> callableList = new ArrayList<Callable<String[]>>(); for (File file : files) { String[] data = getData(file); callableList.add(new SortingThread(data)); //Prepare a Callable list which would be passed to invokeAll() method. counter++; } ExecutorService service = Executors.newFixedThreadPool(counter); // Create a fixed size thread pool, one thread for each file processing... List<Future<String[]>> futureObjects = service.invokeAll(callableList); //List of what call() method of SortingThread is returning... for(counter=0; counter<files.length; counter++) { sortedData = MergeSort.merge(sortedData, futureObjects.get(counter)); } return sortedData; } 进行线程管理是更好的方法。 所以,你可以期待性能。

我没有运行它,所以你可能需要在这里和那里进行更改,但我强调了你的方法。

P.S。:在测量性能时,要获得整洁精确的结果,请始终为每次运行创建一个新的JVM实例。