【问题标题】:How long will this take to run and how can I speed it up这需要多长时间才能运行,我该如何加快速度
【发布时间】:2012-09-30 03:37:09
【问题描述】:

我正在运行一些代码来测试布朗运动和散度,我很好奇这段代码需要多长时间才能运行,以及加速该过程的任何方法。我对java比较陌生,所以目前的代码比较基础。我正在运行的参数是 1000000 1000000。

public class BrownianMotion {

    public static void main(String[] args) {

    /**starts vars for program*/

    int N = Integer.parseInt(args[0]);
    int T = Integer.parseInt(args[1]);
    double sqtotal = 0;
    double r;
    double avg;

    /**number of trials loop*/

    for (int count=0;count<T;count++) {

        /**started here so that x & y reset at each trial*/

        int x = 0;
        int y = 0;

        /**loop for steps*/
        for (int steps=0;steps<N;steps++) {

        r = Math.random();
        if      (r < 0.25) x--;
        else if (r < 0.50) x++;
        else if (r < 0.75) y--;
        else if (r < 1.00) y++;

        }
        /**squared total distance after each trial*/
        sqtotal = sqtotal + (x*x+y*y);

    }

    /**average of squared total*/

    avg = sqtotal/T;
    System.out.println(avg);

    }
}

提前感谢您的帮助。

【问题讨论】:

  • "运行需要多长时间?" - 在上面放一个计时器并测量它。
  • 其复杂度为 O(N*T),因此程序在遇到特定障碍后会显着减速。不过,我真的没有办法改进它。
  • 有没有办法让程序使用更多的处理器时间,我注意到我的 cpu 只运行在 12%。
  • @JakeOrben 我的水晶球告诉我,您正在一台有 8 个 CPU 的机器上测试此代码,并且由于该程序不是多线程的,因此您可以尽可能快地运行单个 CPU(因此你提到的 12% 的 CPU 使用率)。
  • 你的水晶球是正确的,是否可以编写这个程序来运行多线程?

标签: java performance duration


【解决方案1】:

据我了解您的代码,您可以并行运行每个试验。如果您的 CPU 有多个内核,它会相应地运行得更快。

(编辑添加)

通常,我会将算法转换为 Callable,创建 tens 个(每个维度、每个状态等一个),然后使用 Executors.newFixedThreadPool () 来创建一个合理大小的线程池(例如,对于我可能的 Intel i3 笔记本电脑,4 个线程)并调用 invokeAll()。 More details in this blog post

但是,在您的 100,000 示例中,这并不是那么好用。 理想的方法是使用 CompletionService 在作业完成后重新提交作业。这开始变得复杂了。

一种更简单但效率不高(但仍然更快)的方法可能是

  1. 创建一个包含 10 个 BrownianWalkers 的集合。请注意,如果 他们在开始时设置 x 和 y = 0,它们可以重用。所以你只 需要创建一次这个列表
  2. 创建固定线程池
  3. 在 i=0...10000 的循环中{
  4. 调用 submitAll()。
  5. 遍历结果(期货)并将它们添加到您的总和中。
    }

您将浪费一点时间等待所有操作完成,但仍然应该有显着的加速。由于大多数处理器的核心是 2、4、8 等......,稍微改进一下就是使集合成为 2 的幂(而不是 10,这使数学变得容易)

【讨论】:

  • 我该怎么做呢?
【解决方案2】:

为了确定这将运行多长时间,就是找到函数的运行复杂度,O(N^2)。我相信。

【讨论】:

    【解决方案3】:

    这应该是一个有效的并行实现:

    public class BrownianMotionThread extends Thread
    {
        int i;
        int T;
        int N;
        int numberOfProcessors;
        double sqtotal;
    
        BrownianMotionThread(int i, int T, int N, int numberOfProcessors)
        {
            this.i = i;
            this.T = T;
            this.N = N;
            this.numberOfProcessors = numberOfProcessors;
    
        }
    
        public void run()
        {
            double r;
            for (int count=i;count<T;count+= numberOfProcessors) {
    
                /**started here so that x & y reset at each trial*/
    
                int x = 0;
                int y = 0;
                    /**loop for steps*/
                for (int steps=0;steps<N;steps++) {
                    r = Math.random();
                if      (r < 0.25) x--;
                else if (r < 0.50) x++;
                else if (r < 0.75) y--;
                else if (r < 1.00) y++;
                    }
                /**squared total distance after each trial*/
                sqtotal = sqtotal + (x*x+y*y);
                }
        }
    }
    
    public class BrownianMotion {
        static double sqtotal;
        public static void main(String[] args) {
    
        /**starts vars for program*/
    
        final int N = Integer.parseInt(args[0]);
        final int T = Integer.parseInt(args[1]);
        final int numberOfProcessors = Runtime.getRuntime().availableProcessors();
        BrownianMotionThread[] threads = new BrownianMotionThread[numberOfProcessors];
        double avg;
    
        /**number of trials loop*/
        for(int i = 0; i < numberOfProcessors; i++)
        {
            threads[i] = new BrownianMotionThread(i,T,N,numberOfProcessors);
            threads[i].start();
        }
        for(int i = 0; i < numberOfProcessors; i++)
        {
            try 
            {
                threads[i].join();
            } 
            catch (InterruptedException e) 
            {
                e.printStackTrace();
            }
        }
    
        for(int i = 0; i < numberOfProcessors; i++)
        {
            sqtotal += threads[i].sqtotal;
        }
    
    
        /**average of squared total*/
    
        avg = sqtotal/T;
        System.out.println(avg);
    
        }
    
    }
    

    【讨论】:

    • 为什么对我的帖子进行了编辑,从我的帖子中删除了相关和必要的代码?
    【解决方案4】:

    至少有三种方法可以让你的代码运行得更快,从更有效到最不有效:

    1. 降低算法的复杂度。 现在,您的算法具有O(N^2) 时间复杂度:这意味着完成处理所需的时间与算法的平方成正比输入的长度。您可能需要重新访问算法以减少不必要的计算或对中间结果应用优化。

    2. 在算法中引入并行性。您的算法目前被实现为按顺序执行的一大块代码;也就是说(除了硬件级别的指令流水线)每条指令只有在前一条指令完成时才能执行。您可以重写代码以使用线程在多个处理器之间拆分工作,或者您可以使用为您完成大部分工作的并行化框架。这比第 1 点效率低。因为您机器中的处理器数量是恒定的,因此当您提供给算法的输入大小增加时,它不会扩展。

    3. 使用更快的机器。如果算法没有在其他方面得到改进,那么,加速它的唯一方法就是运行得更快。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-01-08
      • 2021-08-15
      • 1970-01-01
      • 2019-12-14
      • 1970-01-01
      • 1970-01-01
      • 2013-10-11
      • 1970-01-01
      相关资源
      最近更新 更多