优化Java中的多态代码走进新版OpenJDK

优化Java中的多态代码

创新互联公司专注于企业成都全网营销推广、网站重做改版、江州网站定制设计、自适应品牌网站建设、H5页面制作商城网站建设、集团公司官网建设、成都外贸网站建设、高端网站制作、响应式网页设计等建站业务,价格优惠性价比高,为江州等各大城市提供网站开发制作服务。

Oracle的Java是一个门快速的语言,有时候它可以和C++一样快。编写Java代码时,我们通常使用接口、继承或者包装类(wrapper class)来实现多态,使软件更加灵活。不幸的是,多态会引入更多的调用,让Java的性能变得糟糕。部分问题是,Java不建议使用完全的内联代码,即使它是非常安全的。(这个问题可能会在***的Java版本里得到缓解,请看文章后面的更新部分)

考虑下这种情况,我们要用接口抽象出一个整型数组:

 
 
  1. public interface Array { 
  2.     public int get(int i); 
  3.     public void set(int i, int x); 
  4.     public int size(); 

你为什么要这样做?可能是因为你的数据是保存在数据库里、网络上、磁盘上或者在其他的数据结构里。你想一次编码后就不用关心数组的具体实现。

编写一个与标准Java数组一样高效率的类并不难,不同之处在于它实现了这个接口:

 
 
  1. public final class NaiveArray implements Array { 
  2.     protected int[] array; 
  3.   
  4.     public NaiveArray(int cap) { 
  5.         array = new int[cap]; 
  6.     } 
  7.   
  8.     public int get(int i) { 
  9.         return array[i]; 
  10.     } 
  11.   
  12.     public void set(int i, int x) { 
  13.         array[i] = x;  
  14.     } 
  15.   
  16.     public int size() { 
  17.         return array.length; 
  18.     } 

至少在理论上,NaiveArray类不会出现任何的性能问题。这个类是final的,所有的方法都很简短。

不幸的是,在一个简单的benchmark类里,当使用NavieArray作为数组实例时,你会发现NavieArray比标准数组慢5倍以上。就像这个例子:

 
 
  1. public int compute() { 
  2.    for(int k = 0; k < array.size(); ++k) 
  3.       array.set(k,k); 
  4.    int sum = 0; 
  5.    for(int k = 0; k < array.size(); ++k) 
  6.       sum += array.get(k); 
  7.    return sum; 

你可以通过使用NavieArray作为NavieArray的一个实例来稍微减缓性能问题(避免使用多态)。不幸的是,它依然会慢3倍多。而你仅是放弃了多态的好处。

那么,强制使用内联函数调用会怎样?

一个可行的解决方法是手动实现内联函数。你可以使用 instanceof 关键字来提供优化实现,否则你只会得到一个普通(更慢)的实现。例如,如果你使用下面的代码,NavieArray就会变得和标准数组一样快:

 
 
  1. public int compute() { 
  2.      if(array instanceof NaiveArray) { 
  3.         int[] back = ((NaiveArray) array).array; 
  4.         for(int k = 0; k < back.length; ++k) 
  5.            back[k] = k; 
  6.         int sum = 0; 
  7.         for(int k = 0; k < back.length; ++k) 
  8.            sum += back[k]; 
  9.         return sum; 
  10.      } 
  11.      //... 

当然,我也会介绍一个维护问题作为需要实现不止一次的同类算法…… 当出现性能问题时,这是一个可接受的替代。

和往常一样,我的benchmarking代码可以在网上获取到。

总结

  • 一些Java版本可能不完全支持频繁的内联函数调用,即使它可以并且应该支持。这会造成严重的性能问题。
  • 把类声明为 final 看起来不会缓解性能问题。
  • 对于消耗大的函数,可行的解决方法是自己手动优化多态和实现内联函数调用。使用 instanceof 关键字,你可以为一些特定的类编写代码并且(因此)保留多态的灵活性。

更新

Erich Schubert使用 double 数组运行简单的benchmark类发现他的运行结果与我的结果相矛盾,而且我们的变量实现都是一样的。我通过更新到***版本的OpenJDK证明了他的结果。下面的表格给出了处理10百万整数需要的纳秒时间:

 Function  Oracle JDK 8u11  OpenJDK 1.8.0_40  OpenJDK 1.7.0_65
straight arrays0.920.710.87
with interface5.90.706.3
with manual inlining0.980.710.93

正如我们看到的,***版本的OpenJDK十分智能,并且消除了多态的性能开销(1.8.0_40)。如果你足够幸运地在使用这个JDK,你不需要担心这 篇文章所说的性能问题。但是,这个总体思想依然值得应用在更复杂的场景里。例如,JDK优化可能依然达不到你期待的性能要求。

原文链接: lemire 翻译: ImportNew.com - 进林

译文链接: http://www.importnew.com/14393.html

网页标题:优化Java中的多态代码走进新版OpenJDK
本文地址:http://www.shufengxianlan.com/qtweb/news41/555791.html

网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等

广告

声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联