Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/302.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 64位以下执行速度慢。可能是RyuJIT错误?_C#_Performance_Visual Studio 2015_Clr_Ryujit - Fatal编程技术网

C# 64位以下执行速度慢。可能是RyuJIT错误?

C# 64位以下执行速度慢。可能是RyuJIT错误?,c#,performance,visual-studio-2015,clr,ryujit,C#,Performance,Visual Studio 2015,Clr,Ryujit,我有以下C#代码试图在发布模式下进行基准测试: using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApplication54 { class Program { static void Main(string[] args

我有以下C#代码试图在发布模式下进行基准测试:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication54
{
class Program
{
    static void Main(string[] args)
    {
        int counter = 0;
        var sw = new Stopwatch();
        unchecked
        {
            int sum = 0;
            while (true)
            {
                try
                {
                    if (counter > 20)
                        throw new Exception("exception");
                }
                catch
                {
                }

                sw.Restart();
                for (int i = 0; i < int.MaxValue; i++)
                {
                    sum += i;
                }
                counter++;
                Console.WriteLine(sw.Elapsed);
            }

        }
    }
}
}
使用系统;
使用System.Collections.Generic;
使用系统诊断;
使用System.Linq;
使用系统文本;
使用System.Threading.Tasks;
命名空间控制台应用程序54
{
班级计划
{
静态void Main(字符串[]参数)
{
int计数器=0;
var sw=新秒表();
未经检查
{
整数和=0;
while(true)
{
尝试
{
如果(计数器>20)
抛出新异常(“异常”);
}
抓住
{
}
sw.Restart();
对于(int i=0;i
我在64位机器上,安装了VS 2015。当我在32位下运行代码时,它会在0.6秒左右运行每个迭代,并打印到控制台。当我在64位下运行它时,每次迭代的持续时间就会跳到4秒!我在我同事的计算机上尝试了示例代码,该计算机只安装了VS 2013。32位和64位版本都在0.6秒左右运行

除此之外,如果我们只删除try-catch块,它也将在0.6秒内运行,VS 2015为64位


当出现try-catch块时,这看起来像是一个严重的RyuJIT回归。我说得对吗?

标杆是一门艺术。对代码进行一个小的修改:

   Console.WriteLine("{0}", sw.Elapsed, sum);
现在你会看到差异消失了。或者换句话说,x86版本现在和x64代码一样慢。您可能会发现RyuJIT没有做什么,而遗留抖动在这个小改动中做了什么,它没有消除不必要的错误

   sum += i;
当您通过“调试”>“Windows”>“反汇编”查看生成的机器代码时,可以看到一些内容。这在龙井确实是个怪癖。它的死代码消除没有遗留抖动那么彻底。除此之外,微软还重写了x64抖动,原因是它无法轻松修复错误。其中之一是优化器的一个相当棘手的问题,它对优化方法所花费的时间没有上限。它会导致具有非常大实体的方法的行为非常糟糕,可能会在林中停留几十毫秒,并导致明显的执行暂停


叫它虫子,嗯,不是真的。编写合理的代码,抖动不会让你失望。优化永远从程序员的耳朵之间的通常位置开始。

经过一点测试,我得到了一些有趣的结果。我的测试围绕着
try-catch
块进行。正如OP所指出的,如果删除这个块,执行的时间是相同的。我进一步缩小了范围,并得出结论,这是因为
try
块中
if
语句中的
counter
变量造成的

让我们删除冗余的
抛出

                try
                {
                    if (counter== 0) { }
                }
                catch
                {
                }
使用此代码将获得与使用原始代码相同的结果

允许将计数器更改为实际的int值:

                try
                {
                    if (1 == 0) { }
                }
                catch
                {
                }
使用此代码,64位版本的执行时间从4秒减少到1.7秒左右。仍然是32位版本的两倍。不过我觉得这很有趣。不幸的是,在我快速的谷歌搜索之后,我还没有找到一个原因,但如果我发现了为什么会发生这种情况,我会进一步挖掘并更新这个答案

至于剩下的那一秒,我们想删掉64位版本,我可以看出这是因为在
for
循环中,将
增加
I
。 让我们对此进行更改,以便
总和
不超过其界限:

            for (int i = 0; i < int.MaxValue; i++)
            {
                sum ++;
            }

您可以看到,我引入了一个新的
intx
,它在
for
循环中被赋值为
sum
。x的值没有写入控制台
sum
不会离开
for
循环。信不信由你,这实际上将x64的执行时间减少到了0.7秒。然而,x86版本会跳到1.4秒。

您的计算机是超级天才!对我来说,每次迭代大约需要10秒:(这里没有区别。32位和64位都给出了非常相同的结果。@M.kazem。我认为这是不可能的。我的计算机是一台Surface Pro 3 i7,具有U级CPU。它绝对不是一个发电站。你确定你在发布模式下运行它,并且不进行调试就启动了吗?顺便说一句,我到目前为止尝试了4台不同的计算机。哦,不,我得到了。因为你需要解决方案属性中的bled选项
Optimize code
。现在我得到32位的
1.3s
,64位的
3.9s
。@M.kazemAkhgary,现在尝试删除try-catch块:)是的。没错。去检查编译后的代码。不管
sum
是否超出其界限-它在未经检查的上下文中运行,所以溢出被忽略-如果代码正在运行。正如Hans指出的,由于
sum
变量在这个循环之后不会被读取,这是可能的(x86,旧的x64 JIT)完全消除循环作为一种优化。@Damien_不相信者你实际上提出了一个非常有趣的观点。。让我用我的发现更新我的答案。@Damien_不相信者我不认为这是未检查的事实实际上很重要。这只意味着当总和达到b时,它肯定不会抛出溢出异常ounds。(与将其更改为checked不同)。无论如何,它仍然需要对64位的边界执行人工检查,因为int有64位分配给它。理论上我猜。再说一次,我不是这些方面的专家,这只是让我感兴趣。
                int x = 0;
                for (int i = 0; i < int.MaxValue; i++)
                {
                    sum += i;
                    x = sum;
                }
                counter++;
                Console.WriteLine(sw.Elapsed + "  " +  x);