- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
如果我给一个变量赋值,然后想给它赋第二个值,但前提是它满足条件,使用简写 if 语句是否同样有效?这是一个例子。
这样效率更高吗
int x = GetInt();
if (x < 5)
x = 5;
比这个
int x = GetInt();
x = x < 5 ? 5 : x;
我想我真正想问的是,如果 x
不满足条件,那么 else 语句中的 x = x
会影响性能吗?
最佳答案
我喜欢这个版本:
int x = Math.Max(5, GetInt());
但请记住,所有这些都是不成熟的优化。今天更快的东西明天可能会更慢,因为像 Windows 更新这样简单的东西会更改框架以添加新的或不同的 JIT 优化。
我可能会花一些时间看看你是否在一个大循环中运行这样的检查:
var items = Enumerable.Range(0, 1000000);
foreach(int item in items)
{
if (item % 3 == 0)
{
//...
}
else
{
//...
}
}
检查循环的原因主要不是因为代码会尽可能快地运行很多次,更强调小的效率低下,而是因为无论你使用 if
还是else
在整个循环中来回变化。
我预计该代码效率低下,因为现代 CPU 的一项功能称为分支预测。如果 if
和 else
的内容足够重要并且足够不同,您可以通过移动执行所有操作使该代码运行得更快很多这些检查(并将所有预测都失败)放在前端,然后一起运行所有 if
,然后运行所有 else
。它会更快,因为运行 if 和 else 的第二阶段的分支预测(运行起来可能要昂贵得多)会更准确。
下面是一个演示差异的小程序:
class Program
{
static int samplesize = 1000000;
//ensure these are big enough that we don't spend time allocating new buffers while the stopwatch is running
static Dictionary<int, string> ints = new Dictionary<int,string>(samplesize * 4);
static Dictionary<double,string> doubles = new Dictionary<double,string>(samplesize * 4);
static void Main(string[] args)
{
var items = Enumerable.Range(0, samplesize).ToArray() ;
var clock = new Stopwatch();
test1(items); //jit hit, discard first run. Also ensure all keys already exist in the dictionary for both tests
clock.Restart();
test1(items);
clock.Stop();
Console.WriteLine("Time for naive unsorted: " + clock.ElapsedTicks.ToString());
test2(items); //jit hit
clock.Restart();
test2(items);
clock.Stop();
Console.WriteLine("Time for separated/branch prediction friendly: " + clock.ElapsedTicks.ToString());
Console.ReadKey(true);
}
static void test1(IEnumerable<int> items)
{
foreach(int item in items)
{
//different code branches that still do significant work in the cpu
// doing more work here results in a larger branch-prediction win, to a point
if (item % 3 == 0)
{ //force hash computation and multiplication op (both cpu-bound)
ints[item] = (item * 2).ToString();
}
else
{
doubles[(double)item] = (item * 3).ToString();
}
}
}
static void test2(IEnumerable<int> items)
{
//doing MORE work: need to evaluate our items two ways, allocate arrays
var intItems = items.Where(i => i % 3 == 0).ToArray();
var doubleItems = items.Where(i => i % 3 != 0).ToArray();
// but now there is no branching... adding all the ints, then adding all the doubles.
foreach (var item in intItems) { ints[item] = (item * 2).ToString(); }
foreach (var item in doubleItems) { doubles[(double)item] = (item * 3).ToString(); }
}
}
在我的机器上的结果是第二个测试,它做更多的工作,运行得更快:
Time for naive unsorted: 1118652
Time for separated/branch prediction friendly: 1005190
这里要带走的重要一点是,不是您需要回头看看是否所有循环都可以从分支预测中获益。这只是众多 CPU 功能中的一个,可以使性能结果让您大吃一惊。这里要带走的重要一点是,要确定代码将如何执行,您实际上需要衡量您的性能。如果您不仔细构建它,那么幼稚的技术仍然可以获胜(我的第一次尝试没有达到我预期的速度)。
此外,我需要指出的是,在这些情况下并没有太大区别。这种性能提升是否值得,或者您将时间花在其他地方会做得更好吗?了解这一点的唯一方法是实际衡量应用程序的整体性能,并找出它真正花费时间的地方。哪里真的比应该的慢?这称为分析,并且有一些工具可以帮助您准确地做到这一点。
关于c# - 以这种方式使用时,内联 if 语句是否有效?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16838733/
我是一名优秀的程序员,十分优秀!