【问题标题】:Visual Studio C# 2010 Express Debug running Faster than ReleaseVisual Studio C# 2010 Express Debug 运行速度比 Release 快
【发布时间】:2012-08-31 19:18:36
【问题描述】:

我有一个正好有 2 个线程的 Windows 窗体应用程序。这些线程彼此之间的交互为零,Ala 第一个线程运行而不会与第二个线程混淆。它们之间没有同步,因为没有必要发生这种情况。第一个线程处理应用程序的 UI,更改颜色和标签,并运行一个计时器以捕获一些用户输入,该计时器每 200 毫秒触发一次。第二个线程涉及更多,并不断运行其编码,直到用户通过退出应用程序关闭。

第二个线程首先从内存中读取数据并将数据存储到一个列表中,然后使用这些数据进行一些计算。我有一个 StopWatch 类计时器来测量完成第二个线程的一次迭代所需的时间。该计时器在线程一开始就重置并启动,然后在线程完成迭代后停止并打印到控制台。这是我获取性能数据的地方。我一直允许线程运行至少 1000 次迭代,然后进行平均,不包括第一次运行。

构建的调试版本,即由 VSHOST 运行的构建,或者在 Visual Studio C# 2010 Express 中按 F5 时运行的构建。计时平均为 0.00035 秒,即 0.35 毫秒。

当应用程序在 VSHOST 之外运行时,通过按 Ctrl-F5 或从按 BUILD 时生成的 .exe 运行应用程序。我还使用 REBUILD 进行了绝对零更改的测试。时间平均为 0.365 秒,即 365 毫秒。发布版本大约慢了 1000 倍。

我完全不知道发生了什么。 VSHOST 的作用是让程序运行得如此之快。我已经确保所有变量初始化都得到了解释和正确。话虽如此,我不知道为什么会发生这样的事情。任何关于我为什么会获得如此性能下降的见解?

作为旁注,我使用的计算机是 64 位的,具有超线程的四核 i7、16 GB 内存和双 HD6750。因此,线程过多似乎不是问题,这里唯一可能存在问题的是超线程。

我的应用程序执行的代码形式的 sn-p。但是,由于读取的内存地址是减速发生的地方,因此无法提供工作代码。

namespace Test Snippet
{
public struct Data
{
    public float X;
    public float Y;
    public float Z;
    public float dX;
    public float dY;

    public Data(int c)
    {
        this.X = ReadFloat(Base + 0x50 + (c * 0x10));
        this.Y = ReadFloat(Base + 0x50 + (c * 0x10));
        this.Z = ReadFloat(Base + 0x50 + (c * 0x10));
        if (this.Z == 1)
        {
            targetindex = c;
        }
        this.dX = 0;
        this.dY = 0;
    }
}
class Class1
{
    public int Base = new int();
    public List<Data> data = new List<Data>();
    public int targetindex = new int();
    public Data targetdata = new Data();

    public void GetData()
    {
        while (true)
        {
            data.Clear();
            for (int c = 0; c < 64; c++)
            {
                Data tempdata = new Data();
                teampdata = new Data(c);
                data.Add(tempdata);
            }
            if (data.Count != 0)
            {
                targetdata = data[targetindex];
                data.RemoveAt(targetindex);
                targetdata.dX = ReadFloat(Base + 0x66);
                targetdata.dY = ReadFloat(Base + 0x65);
                Data[] tempdatarray = new Data[data.Count];
                for (int j = 0; j < tempdatarray.Length; j++)
                {
                    tempdatarray[j].dX = (float)Math.Acos(targetdata.dX * 10);
                    tempdatarray[j].dY = (float)Math.Acos(targetdata.dY * 10);
                }
            }

        }
    }
}

}

编辑:: 我尝试了相同的过程,但没有使用线程。我有由我用来捕获用户输入的计时器调用的线程函数。我得到了同样的结果。所以这意味着线程似乎不是问题。我还在另一台计算机上进行了测试,由于某种原因,我没有得到巨大的差异。这使我相信我的计算机可能有问题,或者由于其超线程能力而处理我的处理器如何处理线程的问题。任何人都知道超线程是否会导致未在程序中明确使用它的多线程应用程序出现问题。老实说,我不知道如何设置。

【问题讨论】:

  • 您是否尝试使用真正的分析工具来分析应用程序?
  • +1 表示一个经过充分研究、写得很好的问题
  • 在没有任何代码测试的情况下很难提供建议。
  • 我目前正在尝试获取可以说明问题的代码的 sn-p 将尽快使用某些源进行编辑。
  • 如果我猜测一下,我猜它是垃圾收集器。在调试模式下,垃圾收集器更加懒惰,因此您拥有的数组可能不会被收集,而是在下一个循环中重新使用,而在释放模式下,垃圾收集器可能会在它超出范围时立即释放它.这是我的最佳猜测。

标签: c# debugging visual-studio-debugging visual-c#-express-2010


【解决方案1】:

我没有看到任何内容表明您正在选择发布版本。这是工具栏上的一个选项。如果您直接运行调试版本,它可能正在寻找它找不到的东西。

编辑:除了我错过的标题!!!! :-)

【讨论】:

  • 这实际上是一个有趣的观点......我不确定它是否一定会对问题的结论产生影响,但正如@MikeKulls 建议的那样,你确定你'正在运行程序集的发布和可能优化的版本?!?
  • 另外一点:假设以上都不是问题,那么你的Debug配置和Release配置是否有相同的Platform Target?
  • 是的,我查看了 .csproj 文件并确保发布和调试它是同一个平台。至于我使用哪种配置,我专门为每次运行重建项目并打开配置的调试然后配置的发布。我什至也尝试过使用发布。作为旁注,我还运行了没有主机进程的调试版本,Ala 将在调试中处理并取消选中使用主机进程。与发布版本的结果相同。这让我相信这与主机进程有关。
  • 哈哈哈它发生了,不用担心你会明白的;)
【解决方案2】:

首先,您应该进行一些性能分析。要么使用分析工具,要么只使用计时器在某处打印一些消息,显示某些事情需要多长时间 - 这应该至少让你确定哪一行代码运行缓慢,即使它没有告诉你它为什么运行在调试器下慢得多。如果没有这些信息,您所拥有的只是猜测。

现在,开始猜测......

根据这些观察,我认为问题与控制台的使用有关

  • 写入控制台窗口本身实际上相对较慢 - 您可以在运行向控制台写入大量内容的应用程序时看到这一点。如果您保持窗口打开,则需要很长时间才能运行,但是如果您最小化控制台窗口,则相同的操作可以更快地运行 很多
  • 据我了解,您每 0.35 毫秒向控制台写入 1 条消息。这是很多信息。
  • 根据您运行应用程序的方式,Visual Studio 实际上会在调试时将控制台输出重定向到 Visual Studo 内的“输出”窗口。

我的猜测是,Visual Studio 中的控制台窗口比不调试时使用的等效机制要快得多,而且额外减速的原因实际上是您的日志记录代码。尝试取出基于控制台的日志记录并记录到文件中,以查看它是否有任何区别,或者甚至只是减少记录消息的次数,例如记录完成 100 次迭代所需的时间 - 这将减少控制台对您的性能的影响(如果有)。

【讨论】:

    【解决方案3】:

    这个问题与超线程无关。我找不到链接,但英特尔在 2004 年对它的工作原理进行了很好的技术描述(没有任何营销炒作)。但它的短处是:Core 0 可能是一个真正的核心,Core 1 可能是一个与 Core 0 共享相同硬件的逻辑核心。对于我们的观点(应用程序开发人员)来说,Core 0 和 Core 1 都是真实的,而我们不是必须关心核心 1 是逻辑核心的事实(除了显而易见的,逻辑核心总体上只提供了大约 13-30% 的性能提升,这在技术描述中再次提到)。 Windows 在跨真实和逻辑核心调度线程方面做得很好。您所要做的就是创建两个线程,Windows 将在核心 0 和核心 1 上各运行一个。您可以在 BIOS 中禁用超线程,以编程方式为线程设置处理器关联,或者从任务管理器中设置关联,如果您愿意进行实验。

    话虽如此,尝试超线程并不能帮助您解决问题。您应该像已经提到的那样做并分析发布版本。还要在事件日志中寻找奇怪的错误。并运行 sysinternal 的 Process Explorer 以查看是否在 I/O 上花费了太多时间。谁知道呢,也许发布版本会以某种方式在这台机器上的设备驱动程序中触发一些古怪的行为。

    编辑:这是英特尔的技术描述(耶维基百科),实际上来自 2002 年:http://download.intel.com/technology/itj/2002/volume06issue01/vol6iss1_hyper_threading_technology.pdf

    【讨论】:

      猜你喜欢
      • 2011-10-26
      • 2011-08-07
      • 1970-01-01
      • 2011-06-30
      • 2015-10-27
      • 1970-01-01
      • 1970-01-01
      • 2011-03-20
      • 1970-01-01
      相关资源
      最近更新 更多