我在学校被告知,修改 for 循环 的索引变量是一种不好的做法:
示例:
for(int i = 0 ; i < limit ; i++){
if(something){
i+=2; //bad
}
if(something){
limit+=2; //bad
}
}
争论的焦点是一些编译器优化可以优化循环,而不是在每个循环中重新计算索引和边界。
我在 java 中做了一些测试,似乎默认情况下每次都会重新计算索引和边界。
我想知道是否可以在 JVM HotSpot 中激活这种功能?
例如优化这种循环:
for(int i = 0 ; i < foo.getLength() ; i++){ }
无需编写:
int length = foo.getLength()
for(int i = 0 ; i < length ; i++){ }
这只是一个例子,我很想尝试看看改进。
编辑
根据 Peter Lawrey 的回答为什么在这个简单的例子中 JVM 不内联 getLength() 方法?:
public static void main(String[] args) {
Too t = new Too();
for(int j=0; j<t.getLength();j++){
}
}
class Too {
int l = 10;
public Too() {
}
public int getLength(){
//System.out.println("test");
return l;
}
}
在输出中“test”打印了 10 次。
我认为优化这种执行可能会很好。
编辑 2: 看来我误会了...
我已经删除了 println,实际上分析器告诉我在这种情况下方法 getLength() 甚至没有被调用一次。
最佳答案
I've made some test in java and it seems that by default index and bound are recalculate each time.
根据 Java 语言规范,这:
for(int i = 0 ; i < foo.getLength() ; i++){ }
表示getLength()在每次循环迭代时调用。 Java 编译器只允许 移动 getLength()如果他们可以有效地证明它不会改变可观察到的行为,则调用循环。
(例如,如果 getLength() 只是返回某个变量的值,那么 JIT 编译器有可能内联调用。如果在内联之后,它可以推断出该变量赢了如果不改变(在某些假设下),它可以应用提升优化。另一方面,如果 getLength() 涉及获取并发或同步集合的长度,则允许提升优化的可能性微乎其微。 . 因为其他线程的潜在操作。)
这就是编译器允许做的事情。
I'm wondering if it's possible to activate this kind of feature in the JVM HotSpot?
简单的答案是否定的。
您似乎在建议一个编译器开关,告诉/允许编译器忽略 JLS 规则。没有这样的开关。这样的转换将是一个坏主意。它可能会导致正确/有效/工作程序中断。考虑一下:
class Test {
int count;
int test(String[] arg) {
for (int i = 0; i < getLength(arg); i++) {
// ...
}
return count;
}
int getLength(String[] arg) {
count++;
return arg.length;
}
}
如果允许编译器移动 getLength(arg)在循环外调用,它会改变调用该方法的次数,因此会改变 test 返回的值方法。
改变正确编写的 Java 程序行为的 Java 优化不是有效的优化。 (请注意,多线程往往会混淆水域。JLS,特别是内存模型规则,允许编译器执行优化,这可能导致不同线程看到应用程序状态的不一致版本......如果它们不同步正确,导致从开发人员的角度来看是不正确的行为。但真正的问题在于应用程序,而不是编译器。)
顺便说一下,您不应该更改循环体中的循环变量的一个更有说服力的理由是它会使您的代码更难理解。
关于java - 用于优化循环语句的 JVM 选项,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9336704/
我脑子里浮现出一些关于一种新编程语言的想法,所以我想我会尝试实现它。一位friend建议我尝试使用Treetop(Rubygem)来创建一个解析器。Treetop的文档很少,我以前从未做过这种事情。我的解析器表现得好像有一个无限循环,但没有堆栈跟踪;事实证明很难追踪到。有人可以指出入门级解析/AST指南的方向吗?我真的需要一些列出规则、常见用法等的东西来使用像Treetop这样的工具。我的语法分析器在GitHub上,以防有人希望帮助我改进它。class{initialize=lambda(name){receiver.name=name}greet=lambda{IO.puts("He
我有多个ActiveRecord子类Item的实例数组,我需要根据最早的事件循环打印。在这种情况下,我需要打印付款和维护日期,如下所示:ItemAmaintenancerequiredin5daysItemBpaymentrequiredin6daysItemApaymentrequiredin7daysItemBmaintenancerequiredin8days我目前有两个查询,用于查找maintenance和payment项目(非排他性查询),并输出如下内容:paymentrequiredin...maintenancerequiredin...有什么方法可以改善上述(丑陋的)代
大约一年前,我决定确保每个包含非唯一文本的Flash通知都将从模块中的方法中获取文本。我这样做的最初原因是为了避免一遍又一遍地输入相同的字符串。如果我想更改措辞,我可以在一个地方轻松完成,而且一遍又一遍地重复同一件事而出现拼写错误的可能性也会降低。我最终得到的是这样的:moduleMessagesdefformat_error_messages(errors)errors.map{|attribute,message|"Error:#{attribute.to_s.titleize}#{message}."}enddeferror_message_could_not_find(obje
这是在Ruby中设置默认值的常用方法:classQuietByDefaultdefinitialize(opts={})@verbose=opts[:verbose]endend这是一个容易落入的陷阱:classVerboseNoMatterWhatdefinitialize(opts={})@verbose=opts[:verbose]||trueendend正确的做法是:classVerboseByDefaultdefinitialize(opts={})@verbose=opts.include?(:verbose)?opts[:verbose]:trueendend编写Verb
我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/
我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("
我已经在Sinatra上创建了应用程序,它代表了一个简单的API。我想在生产和开发上进行部署。我想在部署时选择,是开发还是生产,一些方法的逻辑应该改变,这取决于部署类型。是否有任何想法,如何完成以及解决此问题的一些示例。例子:我有代码get'/api/test'doreturn"Itisdev"end但是在部署到生产环境之后我想在运行/api/test之后看到ItisPROD如何实现? 最佳答案 根据SinatraDocumentation:EnvironmentscanbesetthroughtheRACK_ENVenvironm
我一直致力于让我们的Rails2.3.8应用程序在JRuby下正确运行。一切正常,直到我启用config.threadsafe!以实现JRuby提供的并发性。这导致lib/中的模块和类不再自动加载。使用config.threadsafe!启用:$rubyscript/runner-eproduction'pSim::Sim200Provisioner'/Users/amchale/.rvm/gems/jruby-1.5.1@web-services/gems/activesupport-2.3.8/lib/active_support/dependencies.rb:105:in`co
我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www
我注意到类定义,如果我打开classMyClass,并在不覆盖的情况下添加一些东西我仍然得到了之前定义的原始方法。添加的新语句扩充了现有语句。但是对于方法定义,我仍然想要与类定义相同的行为,但是当我打开defmy_method时似乎,def中的现有语句和end被覆盖了,我需要重写一遍。那么有什么方法可以使方法定义的行为与定义相同,类似于super,但不一定是子类? 最佳答案 我想您正在寻找alias_method:classAalias_method:old_func,:funcdeffuncold_func#similartoca