A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 熊永标 中级黑马   /  2013-2-26 17:33  /  2860 人查看  /  13 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

  1. long temp=0;
  2. for(long i=0;i<10000000000000000;i++)
  3. {
  4. temp++;
  5. }
  6. //这个for循环运行相当的慢,有没有什么办法提高这种性能呀?我有这样的应用,请求帮助.
复制代码

13 个回复

倒序浏览
  1. long temp=0;
  2. for(long i=0,j=10000000000000000;i<j;i++)
  3. {
  4. temp++;
  5. }
复制代码
这么写试试,这是提高for循环的一种方法,但是对于这段代码可能影响不大
回复 使用道具 举报
首先更正一点你的写法你的写法long会把long认为成是int 类型要这样写
  1. long temp=0L;
  2.         for(long i=0;i<10000000000L;i++)
  3.         {
  4.         temp++;
  5.         }
复制代码
long startTime=System.currentTimeMillis();   //获取开始时间
        long temp=0L;
        for(long i=0;i<10000000000L;i++)
        {
        temp++;
        }
        long endTime=System.currentTimeMillis(); //获取结束时间
        System.out.println("程序运行时间: "+(endTime-startTime)+"ms");
        // 我测试的几组数据1程序运行时间:1 . 130126ms 2.程序运行时间: 62219ms 3.程序运行时间: 60375ms 4.程序运行时间: 48500ms
优化后
long startTime=System.currentTimeMillis();   //获取开始时间
        long temp=0L;
        long i=0;
        for(;i<10000000000L;i++)
        {
        temp++;
        }
        long endTime=System.currentTimeMillis(); //获取结束时间
        System.out.println("程序运行时间: "+(endTime-startTime)+"ms");
        //1 程序运行时间: 38054ms 2程序运行时间: 51683ms 3.程序运行时间: 37786ms

我的观点如此大的for循环 是不存在的 如果里面的逻辑代码稍微大点 肯定会报内存溢出的错误,
以前在项目中遇到了 我似乎 把for循环 i =x*j的for循环嵌套 加break 语句做的。
效率不高但是把内存溢出问题解决了。
如果想提高效率 本人建议如果下
1.如果做优化 主要是真对 for循环里面的代码 向初始化什么的东东 东放在for 循环的外面
可以把i 分解 很多小块 如果 】
2.分成小块后可以 用多线程的方式执行

评分

参与人数 1技术分 +1 收起 理由
陈丽莉 + 1

查看全部评分

回复 使用道具 举报
如果把你的执行语句放在while()循环里不是更简单么
long temp=0;
while(temp<10000000000000000)
{
                           //你要实现的执行语句
  temp++;
}
这样就可以省去 栈内存中对 ”i “ 的操作 ,节省内存空间的同时,只操作 temp 来实现while语句,从而节约了for循环语句的遍历,来提高运行效率

不知道你要实现的功能,很难断定 temp 进行操作后的 0<temp & & temp<10000000000000000 时 数据是否还会进行循环语句外的运算 当然,在多线程方面就如同楼上所述,防止线程溢出,保证该线程单独运行至结束也可以,但意义不大,考虑到个人机器的 cpu所控制的进程分配,及内存大小,这里不再赘述。

个人观点,多指教
回复 使用道具 举报
前边写的很详细,给你们加一句,把i++换成++i,也许效果不太明显,不过这能提高效率是真的。

评分

参与人数 1技术分 +1 收起 理由
陈丽莉 + 1

查看全部评分

回复 使用道具 举报
  可以很负责人的说,++I和i++之间的性能是一样,无论是从汇编语言角度看,还是从java字节码来看,性能都是一样的,只是指令顺序不一样。
   下面是我的解决方案:
  第一,向你这样的for循环里有一个long,很大的性能损失来源于java虚拟机的字节大小,因为32位虚拟机的字大小为4字节,那么访问一个long就需要两个读周期。如果你使用java64位的虚拟机,就只需要一个读周期便可以了。这可以减少一半的时间。
第二,就像上面所说的,实际中很少有这么大的循环。其次你这个for循环里的  ii<10000000000000000;在实际编码中是不会这样做的,我么一般都将这个10000000000000000放进一个变量中,然后在运行时求值,这样来动态调整循环量。举个非常典型的例子,如下:
for(int index=0;index<array.getLength();i++)
{
     .....
}
这个循环遍历一个数组,可是这里并没有硬编码大小,而是让index<array.getLength()来运行时自动调整。

评分

参与人数 1技术分 +1 收起 理由
张庚 + 1

查看全部评分

回复 使用道具 举报
王宝生 发表于 2013-2-28 12:59
可以很负责人的说,++I和i++之间的性能是一样,无论是从汇编语言角度看,还是从java字节码来看,性能都是 ...

++i 和 i++  性能是不一样的,  ++i 是先将i 的值自增1,再参与运算;  而 i++ 是先将i 的值参与运算后,再自增1。  提到编程语言,至少vc中,++i 的所实现的语句要比 i++ 少一条;
由于 i++ 是先用i 的值运算后,再将i 自增,所以是需要一个缓存变量的,因此确实可以增加一点效率。当然,如果都是单独成为一条语句,速度差不多就是了。
回复 使用道具 举报
  呵呵,这是C++中的一段代码,用vc++6.0编译的,debug版本.
int main(int argc, char* argv[])
{       
        int a=argc;
        int j=a++;
        printf("a=%d\n",a);
       
        int c=++a;
        printf("%d %d",a,c);
        return 0;
}
反汇编代码如下:
Mov ecx,dword ptr[ebp-4;cx=a;
Mov dword ptr[ebp-1]  ecx;=a
Mov edx,dword ptr[ebp-4];次访问a
Add edx,1
Mov dword ptr[ebp-4],;将a++的值存回a
这段代码,首先从内存中取a到寄存器,然后在存回内存j中。访问了两次内存。
然后再从内存中取出a,执行加法运算,两条mov,一条adx,共三条指令。

Mov ecx,dword ptr[ebp-4];a
Add ecx,1
Mov dword ptr [ebp-4],ecx;执行加法后结果存回a
Mov edx,dword ptr[ebp-4]次取a
Mov dword ptr[ebp-0Ch],edx;c=a;
这段代码,先计算a=a+1;其次将a赋值给c;

   编代码整体性能是一样的,如果要是按参与运算顺序的话,那么毫无疑问,肯定是++a要快,因为他们之间要差一条指令,但这是微不足道的。因为在一个循环中,后面的指令终归还是要执行的。
   对于这里的i++,从来没有在内存中创建一个副本,只是将他保存到了一个中间量寄存器中。
   对于for循环,如果是release版本,编译器会对其进行许多优化,譬如将其转换为do-while结构,或者将for循环内的某些指令提取到for循环外来缩短for内指令数增加执行次数。

   更重要的是,影响for循环性能的还有一个重要原因,那就是局部性的问题。如果访问问的数据或者指令没有出现在高速缓存中(第一次),或者数组分配的大小不合理(导致数据频繁的在高速缓存间换入换出),或者访问的步长太大(访问一个元素跳几个,间歇行访问)或者for循环内指令数太多,导致每一次循环都要好长时间。

   如果是看字节码的话,也是这样,只不过在字节码中没有寄存器,所以只能使用dup指令将数据复制到计算栈顶,然后对这个复制版本进行操作。
回复 使用道具 举报
本帖最后由 王宝生 于 2013-3-2 09:13 编辑
陈丽莉 发表于 2013-3-1 20:09
++i 和 i++  性能是不一样的,  ++i 是先将i 的值自增1,再参与运算;  而 i++ 是先将i 的值参与运算后, ...

  呵呵,这是C++中的一段代码,用vc++6.0编译的,debug版本.
int main(int argc, char* argv[])
{        
        int a=argc;
        int j=a++;
        printf("a=%d\n",a);
        
        int c=++a;
        printf("%d %d",a,c);
        return 0;
}
反汇编代码如下:
Mov ecx,dword ptr[ebp-4;cx=a;
Mov dword ptr[ebp-1]  ecx;=a
Mov edx,dword ptr[ebp-4];次访问a
Add edx,1
Mov dword ptr[ebp-4],;将a++的值存回a
这段代码,首先从内存中取a到寄存器,然后在存回内存j中。访问了两次内存。
然后再从内存中取出a,执行加法运算,两条mov,一条adx,共三条指令。

Mov ecx,dword ptr[ebp-4];a
Add ecx,1
Mov dword ptr [ebp-4],ecx;执行加法后结果存回a
Mov edx,dword ptr[ebp-4]次取a
Mov dword ptr[ebp-0Ch],edx;c=a;
这段代码,先计算a=a+1;其次将a赋值给c;

   编代码整体性能是一样的,如果要是按参与运算顺序的话,那么毫无疑问,肯定是++a要快,因为他们之间要差一条指令,但这是微不足道的。因为在一个循环中,后面的指令终归还是要执行的。
   对于这里的i++,从来没有在内存中创建一个副本,只是将他保存到了一个中间量寄存器中。
   对于for循环,如果是release版本,编译器会对其进行许多优化,譬如将其转换为do-while结构,或者将for循环内的某些指令提取到for循环外来缩短for内指令数增加执行次数。

   更重要的是,影响for循环性能的还有一个重要原因,那就是局部性的问题。如果访问问的数据或者指令没有出现在高速缓存中(第一次),或者数组分配的大小不合理(导致数据频繁的在高速缓存间换入换出),或者访问的步长太大(访问一个元素跳几个,间歇行访问)或者for循环内指令数太多,导致每一次循环都要好长时间。

   如果是看字节码的话,也是这样,只不过在字节码中没有寄存器,所以只能使用dup指令将数据复制到计算栈顶,然后对这个复制版本进行操作。

评分

参与人数 1技术分 +1 收起 理由
陈丽莉 + 1 鼓励一下~

查看全部评分

回复 使用道具 举报
王宝生 发表于 2013-3-2 09:12
呵呵,这是C++中的一段代码,用vc++6.0编译的,debug版本.
int main(int argc, char* argv[])
{        

回答问题的人都说了,效果不明显,即使微不足道,也是稍有差别的,你找了一大堆来验证差别的细微性,到底他们两个还是不一样的,又何必纠结这个问题呢。
回复 使用道具 举报
++i 建议在程序中少用 理解不好很容易出错
回复 使用道具 举报
如果也问题已解决,请改为已经解决,没有,就追问,谢谢合作
回复 使用道具 举报
本帖最后由 杨玉辉 于 2013-3-3 15:19 编辑

哎 ,要不说 在执行数据过长的循环遍历时,最好还是不要使用for(){} 循环 耗费内存资源呀
其次 ,windows 本身就存在cpu 多进程 处理,出现 线程等待 是很正常的事情

何必呢,要淡定...
回复 使用道具 举报
用while确实是能够提高效率,但是能提高多少就不清楚了,可能效果并不明显吧
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马