我希望这个问题对于这个论坛来说不算太基础,但我们会看到.我想知道如何重构一些代码以获得更好的性能,这些代码会运行很多次.
假设我正在使用Map(可能是HashMap)创建一个单词频率列表,其中每个键都是一个字符串,其中包含要计数的单词,而值是一个整数,每次找到该单词的标记时,该整数都会递增.
在Perl中,增加这样的值将非常简单:
$map{$word}++;
Run Code Online (Sandbox Code Playgroud)
但在Java中,它要复杂得多.这是我目前正在做的方式:
int count = map.containsKey(word) ? map.get(word) : 0;
map.put(word, count + 1);
Run Code Online (Sandbox Code Playgroud)
这当然依赖于较新Java版本中的自动装箱功能.我想知道你是否可以提出一种更有效的方法来增加这样的价值.是否有良好的性能原因可以避开Collections框架并使用其他东西?
更新:我已经对几个答案进行了测试.见下文.
这是我能提出的最佳算法.
def get_primes(n):
numbers = set(range(n, 1, -1))
primes = []
while numbers:
p = numbers.pop()
primes.append(p)
numbers.difference_update(set(range(p*2, n+1, p)))
return primes
>>> timeit.Timer(stmt='get_primes.get_primes(1000000)', setup='import get_primes').timeit(1)
1.1499958793645562
Run Code Online (Sandbox Code Playgroud)
可以做得更快吗?
此代码有一个缺陷:由于numbers是无序集,因此无法保证numbers.pop()从集中删除最小数字.然而,它对某些输入数字起作用(至少对我而言):
>>> sum(get_primes(2000000))
142913828922L
#That's the correct sum of all numbers below 2 million
>>> 529 in get_primes(1000)
False
>>> 529 in get_primes(530)
True
Run Code Online (Sandbox Code Playgroud) 我正在阅读Agner Fog的优化手册,并且遇到了这个例子:
double data[LEN];
void compute()
{
const double A = 1.1, B = 2.2, C = 3.3;
int i;
for(i=0; i<LEN; i++) {
data[i] = A*i*i + B*i + C;
}
}
Run Code Online (Sandbox Code Playgroud)
Agner 指出,有一种方法可以优化此代码 - 通过认识到循环可以避免使用昂贵的乘法,而是使用每次迭代应用的“增量”。
我用一张纸来证实这个理论,首先......
...当然,他是对的 - 在每次循环迭代中,我们可以通过添加“增量”,基于旧结果计算新结果。该增量从值“A+B”开始,然后每一步增加“2*A”。
所以我们将代码更新为如下所示:
void compute()
{
const double A = 1.1, B = 2.2, C = 3.3;
const double A2 = A+A;
double Z = A+B;
double Y = C;
int i;
for(i=0; i<LEN; i++) {
data[i] …Run Code Online (Sandbox Code Playgroud) 我一直在绞尽脑汁想要完成这项任务一周,我希望有人能带领我走向正确的道路.让我从教师的指示开始:
您的作业与我们的第一个实验作业相反,即优化素数计划.你在这个任务中的目的是使程序失望,即让它运行得更慢.这两个都是CPU密集型程序.他们需要几秒钟才能在我们的实验室电脑上运行.您可能无法更改算法.
要取消优化程序,请使用您对英特尔i7管道如何运行的了解.想象一下重新排序指令路径以引入WAR,RAW和其他危险的方法.想一想最小化缓存有效性的方法.恶魔无能.
该作业选择了Whetstone或Monte-Carlo程序.缓存有效性评论大多只适用于Whetstone,但我选择了Monte-Carlo模拟程序:
// Un-modified baseline for pessimization, as given in the assignment
#include <algorithm> // Needed for the "max" function
#include <cmath>
#include <iostream>
// A simple implementation of the Box-Muller algorithm, used to generate
// gaussian random numbers - necessary for the Monte Carlo method below
// Note that C++11 actually provides std::normal_distribution<> in
// the <random> library, which can be used instead of this function
double gaussian_box_muller() {
double x = 0.0;
double y = 0.0; …Run Code Online (Sandbox Code Playgroud) 我有遗留的C++代码,我应该从中删除未使用的代码.问题是代码库很大.
如何找出从未调用/从未使用过的代码?
有没有办法分析Vim插件?
当我打开一个大的时候,我的MacVim变得越来越慢.py.我知道我可以取消选择所有插件并逐个重新选择以检查哪个插件是罪魁祸首,但有更快的方法吗?
我的dotvim在这里:https://github.com/charlax/dotvim
我在这里浏览strlen代码,想知道是否真的需要代码中使用的优化?例如,为什么下面这样的东西不能同样好或更好?
unsigned long strlen(char s[]) {
unsigned long i;
for (i = 0; s[i] != '\0'; i++)
continue;
return i;
}
Run Code Online (Sandbox Code Playgroud)
较简单的代码对编译器进行优化是否更好或更容易?
strlen链接后面页面上的代码如下所示:
Run Code Online (Sandbox Code Playgroud)/* Copyright (C) 1991, 1993, 1997, 2000, 2003 Free Software Foundation, Inc. This file is part of the GNU C Library. Written by Torbjorn Granlund (tege@sics.se), with help from Dan Sahlin (dan@sics.se); commentary by Jim Blandy (jimb@ai.mit.edu). The GNU C Library is free software; you can redistribute it and/or modify it under …
我正在阅读一个很棒的OpenGL教程.这真的很棒,相信我.我目前的主题是Z-buffer.除了解释它的全部内容之外,作者还提到我们可以执行自定义深度测试,例如GL_LESS,GL_ALWAYS等.他还解释了深度值的实际含义(顶部是哪个,哪个不是)也可以定制.到目前为止我明白了.然后作者说了一些令人难以置信的事:
zNear的范围可以大于zFar的范围; 如果是,则窗口空间值将根据与观看者最近或最远的内容来反转.
早些时候,据说窗口空间Z值为0,最接近1.但是,如果我们的剪辑空间Z值被否定,则1的深度将最接近视图,0的深度将最远.然而,如果我们翻转深度测试的方向(GL_LESS到GL_GREATER等),我们得到完全相同的结果.所以这真的只是一个惯例.事实上,翻转Z的标志和深度测试曾经是许多游戏的重要性能优化.
如果我理解正确,性能方面,翻转Z的符号和深度测试只不过是将<比较改为>比较.所以,如果我理解正确并且作者没有说谎或做事,那么<改为>以前是许多游戏的重要优化.
是作者胡编,我误解的东西,或者是它确实是曾经的情况下<较慢(至关重要,正如作者说)比>?
谢谢你澄清这个非常奇怪的事情!
免责声明:我完全清楚算法复杂性是优化的主要来源.此外,我怀疑现在肯定没有任何区别,我不是要求它优化任何东西.我非常痛苦,也许是令人望而却步的好奇心.