简体   繁体   English

为什么我的C#程序在分析器中更快?

[英]Why is my C# program faster in a profiler?

I have a relatively large system (~25000 lines so far) for monitoring radio-related devices. 我有一个相对较大的系统(到目前为止约25000行)用于监控无线电相关设备。 It shows graphs and such using latest version of ZedGraph. 它使用最新版本的ZedGraph显示图表等。 The program is coded using C# on VS2010 with Win7. 该程序使用Win7上的VS2010上的C#进行编码。 The problem is: 问题是:

  • when I run the program from within VS, it runs slow 当我从VS内部运行程序时,它运行缓慢
  • when I run the program from the built EXE, it runs slow 当我从构建的EXE运行程序时,它运行缓慢
  • when I run the program though Performance Wizard / CPU Profiler, it runs Blazing Fast. 当我通过Performance Wizard / CPU Profiler运行程序时,它会运行Blazing Fast。
  • when I run the program from the built EXE, and then start VS and Attach a profiler to ANY OTHER PROCESS, my program speeds up! 当我从构建的EXE运行程序,然后启动VS并将分析器附加到任何其他进程时,我的程序加速了!

I want the program to always run that fast! 我希望程序能够快速运行!

Every project in the solution is set to RELEASE, Debug unmanaged code is DISABLED, Define DEBUG and TRACE constants is DISABLED, Optimize Code - I tried either, Warning Level - I tried either, Suppress JIT - I tried either, in short I tried all the solutions already proposed on StackOverflow - none worked. 解决方案中的每个项目都设置为RELEASE,Debug非托管代码为DISABLED,定义DEBUG和TRACE常量为DISABLED,优化代码 - 我尝试了,警告级别 - 我试过,抑制JIT - 我试过,或者我试过所有StackOverflow上已经提出的解决方案 - 没有成功。 Program is slow outside profiler, fast in profiler. 程序在分析器外部很慢,在分析器中很快。 I don't think the problem is in my code, because it becomes fast if I attach the profiler to other, unrelated process as well! 我不认为问题出在我的代码中,因为如果我将探查器附加到其他不相关的进程中它会变得很快!

Please help! 请帮忙! I really need it to be that fast everywhere, because it's a business critical application and performance issues are not tolerated... 我真的需要它在各地快速,因为它是一个关键业务应用程序和性能问题是不能容忍的...

UPDATES 1 - 8 follow 更新1 - 8跟随

--------------------Update1:-------------------- -------------------- UPDATE1:--------------------

The problem seems to Not be ZedGraph related, because it still manifests after I replaced ZedGraph with my own basic drawing. 问题似乎与ZedGraph无关,因为在我用自己的基本绘图替换ZedGraph之后它仍然存在。

--------------------Update2:-------------------- -------------------- UPDATE2:--------------------

Running the program in a Virtual machine, the program still runs slow, and running profiler from the Host machine doesn't make it fast. 在虚拟机中运行该程序,该程序仍然运行缓慢,并且从主机运行的探查器不会使它快速。

--------------------Update3:-------------------- -------------------- UPDATE3:--------------------

Starting screen capture to video also speeds the program up! 启动屏幕捕获到视频也可以加快程序的速度!

--------------------Update4:-------------------- -------------------- UPDATE4:--------------------

If I open the Intel graphics driver settings window (this thing: http://www.intel.com/support/graphics/sb/img/resolution_new.jpg ) and just constantly hover with the cursor over buttons, so they glow, etc, my program speeds up!. 如果我打开英特尔图形驱动程序设置窗口(这个东西: http//www.intel.com/support/graphics/sb/img/resolution_new.jpg ),只是不断地将光标悬停在按钮上,这样它们就会发光,等等,我的节目加快了! It doesn't speed up if I run GPUz or Kombustor though, so no downclocking on the GPU - it stays steady 850Mhz. 如果我运行GPUz或Kombustor,它不会加速,因此没有GPU上的超频 - 它保持稳定850Mhz。

--------------------Update5:-------------------- -------------------- Update5:--------------------

Tests on different machines: 测试不同的机器:

-On my Core i5-2400S with Intel HD2000, UI runs slow and CPU usage is ~15%. - 在配备Intel HD2000的Core i5-2400S上,UI运行缓慢,CPU使用率约为15%。

-On a colleague's Core 2 Duo with Intel G41 Express, UI runs fast, but CPU usage is ~90% (which isn't normal either) - 在配备英特尔G41 Express的同事的Core 2 Duo上,UI运行速度很快,但CPU使用率约为90%(这也不正常)

-On Core i5-2400S with dedicated Radeon X1650, UI runs blazing fast, CPU usage is ~50%. - 在配备专用Radeon X1650的酷睿i5-2400S上,UI运行速度极快,CPU使用率约为50%。

--------------------Update6:-------------------- -------------------- Update6:--------------------

A snip of code showing how I update a single graph ( graphFFT is an encapsulation of ZedGraphControl for ease of use): 的示出如何我更新单个图形码A剪断( graphFFT是的封装ZedGraphControl为了便于使用):

public void LoopDataRefresh() //executes in a new thread
        {
            while (true)
            {
                while (!d.Connected)
                    Thread.Sleep(1000);
                if (IsDisposed)
                    return;
//... other graphs update here
                if (signalNewFFT && PanelFFT.Visible)
                {
                    signalNewFFT = false;
                    #region FFT
                    bool newRange = false;
                    if (graphFFT.MaxY != d.fftRangeYMax)
                    {
                        graphFFT.MaxY = d.fftRangeYMax;
                        newRange = true;
                    }
                    if (graphFFT.MinY != d.fftRangeYMin)
                    {
                        graphFFT.MinY = d.fftRangeYMin;
                        newRange = true;
                    }

                    List<PointF> points = new List<PointF>(2048);
                    int tempLength = 0;
                    short[] tempData = new short[2048];

                    int i = 0;

                    lock (d.fftDataLock)
                    {
                        tempLength = d.fftLength;
                        tempData = (short[])d.fftData.Clone();
                    }
                    foreach (short s in tempData)
                        points.Add(new PointF(i++, s));

                    graphFFT.SetLine("FFT", points);

                    if (newRange)
                        graphFFT.RefreshGraphComplete();
                    else if (PanelFFT.Visible)
                        graphFFT.RefreshGraph();

                    #endregion
                }
//... other graphs update here
                Thread.Sleep(5);
            }
        }

SetLine is: SetLine是:

public void SetLine(String lineTitle, List<PointF> values)
    {
        IPointListEdit ip = zgcGraph.GraphPane.CurveList[lineTitle].Points as IPointListEdit;
        int tmp = Math.Min(ip.Count, values.Count);
        int i = 0;
        while(i < tmp)
        {
            if (values[i].X > peakX)
                peakX = values[i].X;
            if (values[i].Y > peakY)
                peakY = values[i].Y;
            ip[i].X = values[i].X;
            ip[i].Y = values[i].Y;
            i++;
        }
        while(ip.Count < values.Count)
        {
            if (values[i].X > peakX)
                peakX = values[i].X;
            if (values[i].Y > peakY)
                peakY = values[i].Y;
            ip.Add(values[i].X, values[i].Y);
            i++;
        }
        while(values.Count > ip.Count)
        {
            ip.RemoveAt(ip.Count - 1);
        }
    }

RefreshGraph is: RefreshGraph是:

public void RefreshGraph()
    {
        if (!explicidX && autoScrollFlag)
        {
            zgcGraph.GraphPane.XAxis.Scale.Max = Math.Max(peakX + grace.X, rangeX);
            zgcGraph.GraphPane.XAxis.Scale.Min = zgcGraph.GraphPane.XAxis.Scale.Max - rangeX;
        }
        if (!explicidY)
        {
            zgcGraph.GraphPane.YAxis.Scale.Max = Math.Max(peakY + grace.Y, maxY);
            zgcGraph.GraphPane.YAxis.Scale.Min = minY;
        }
        zgcGraph.Refresh();
    }

.

--------------------Update7:-------------------- -------------------- Update7:--------------------

Just ran it through the ANTS profiler. 只需通过ANTS探查器运行它。 It tells me that the ZedGraph refresh counts when the program is fast are precisely two times higher compared to when it's slow. 它告诉我,程序快速时ZedGraph刷新计数的速度恰好是慢速时的两倍。 Here are the screenshots: 以下是截图: ANTS的屏幕截图很慢ANTS快速截图

I find it VERY strange that, considering the small difference in the length of the sections, performance differs twice with mathematical precision. 我觉得非常奇怪,考虑到截面长度的微小差异,性能与数学精度相差两次。

Also, I updated the GPU driver, that didn't help. 此外,我更新了GPU驱动程序,但没有帮助。

--------------------Update8:-------------------- -------------------- Update8:--------------------

Unfortunately, for a few days now, I'm unable to reproduce the issue... I'm getting constant acceptable speed (which still appear a bit slower than what I had in the profiler two weeks ago) which isn't affected by any of the factors that used to affect it two weeks ago - profiler, video capturing or GPU driver window. 不幸的是,几天之后,我无法重现这个问题......我的速度一直是可接受的(这仍然比我两周前在剖析器中的速度慢一点),这个速度不受影响两周前用于影响它的任何因素 - 分析器,视频捕获或GPU驱动程序窗口。 I still have no explanation of what was causing it... 我仍然没有解释导致它的原因......

There are situations when slowing down a thread can speed up other threads significantly, usually when one thread is polling or locking some common resource frequently. 在某些情况下,减慢线程可以显着加快其他线程的速度,通常是在一个线程轮询或频繁锁定某些公共资源时。

For instance (this is a windows-forms example) when the main thread is checking overall progress in a tight loop instead of using a timer, for example: 例如(这是一个Windows窗体示例)当主线程在紧密循环中检查整体进度而不是使用计时器时,例如:

private void SomeWork() {
  // start the worker thread here
  while(!PollDone()) {
    progressBar1.Value = PollProgress();
    Application.DoEvents(); // keep the GUI responisive
  }
}

Slowing it down could improve performance: 减慢速度可以提高性能:

private void SomeWork() {
  // start the worker thread here
  while(!PollDone()) {
    progressBar1.Value = PollProgress();
    System.Threading.Thread.Sleep(300); // give the polled thread some time to work instead of responding to your poll
    Application.DoEvents(); // keep the GUI responisive
  }
}

Doing it correctly, one should avoid using the DoEvents call alltogether: 正确地做,应该避免一起使用DoEvents调用:

private Timer tim = new Timer(){ Interval=300 };

private void SomeWork() {
  // start the worker thread here
  tim.Tick += tim_Tick;
  tim.Start();
}

private void  tim_Tick(object sender, EventArgs e){
  tim.Enabled = false; // prevent timer messages from piling up
  if(PollDone()){
    tim.Tick -= tim_Tick;
    return;
  }
  progressBar1.Value = PollProgress();
  tim.Enabled = true;
}

Calling Application.DoEvents() can potentially cause allot of headaches when GUI stuff has not been disabled and the user kicks off other events or the same event a 2nd time simultaneously, causing stack climbs which by nature queue the first action behind the new one, but I'm going off topic. 调用Application.DoEvents()可能会在GUI内容未被禁用并且用户同时启动其他事件或同一事件时引起分配令人头疼,从而导致堆栈爬升,其本质排队后面的第一个操作,但是我要离题了。

Probably that example is too winforms specific, I'll try making a more general example. 可能这个例子太具体了,我会尝试做一个更一般的例子。 If you have a thread that is filling a buffer that is processed by other threads, be sure to leave some System.Threading.Thread.Sleep() slack in the loop to allow the other threads to do some processing before checking if the buffer needs to be filled again: 如果你的线程正在填充由其他线程处理的缓冲区,请确保在循环中留下一些System.Threading.Thread.Sleep()松弛,以允许其他线程在检查缓冲区是否需要之前进行一些处理再次填补:

public class WorkItem { 
  // populate with something usefull
}

public static object WorkItemsSyncRoot = new object();
public static Queue<WorkItem> workitems = new Queue<WorkItem>();

public void FillBuffer() {
  while(!done) {
    lock(WorkItemsSyncRoot) {
      if(workitems.Count < 30) {
        workitems.Enqueue(new WorkItem(/* load a file or something */ ));
      }
    }
  }
}

The worker thread's will have difficulty to obtain anything from the queue since its constantly being locked by the filling thread. 工作线程很难从队列中获取任何东西,因为它经常被填充线程锁定。 Adding a Sleep() (outside the lock) could significantly speed up other threads: 添加Sleep()(在锁之外)可以显着加快其他线程:

public void FillBuffer() {
  while(!done) {
    lock(WorkItemsSyncRoot) {
      if(workitems.Count < 30) {
        workitems.Enqueue(new WorkItem(/* load a file or something */ ));
      }
    }
    System.Threading.Thread.Sleep(50);
  }
}

Hooking up a profiler could in some cases have the same effect as the sleep function. 在某些情况下,连接分析器可以与睡眠功能具有相同的效果。

I'm not sure if I've given representative examples (it's quite hard to come up with something simple) but I guess the point is clear, putting sleep() in the correct place can help improve the flow of other threads. 我不确定我是否给出了代表性的例子(很难想出一些简单的东西)但我想这一点很清楚,将sleep()置于正确的位置可以帮助改善其他线程的流量。

---------- Edit after Update7 ------------- ---------- Update7后编辑-------------

I'd remove that LoopDataRefresh() thread altogether. 我将完全删除LoopDataRefresh()线程。 Rather put a timer in your window with an interval of at least 20 (which would be 50 frames a second if none were skipped): 而是将一个计时器放在窗口中,间隔至少为20(如果没有跳过,则为每秒50帧):

private void tim_Tick(object sender, EventArgs e) {
  tim.Enabled = false; // skip frames that come while we're still drawing
  if(IsDisposed) {
    tim.Tick -= tim_Tick;
    return;
  }

  // Your code follows, I've tried to optimize it here and there, but no guarantee that it compiles or works, not tested at all

  if(signalNewFFT && PanelFFT.Visible) {
    signalNewFFT = false;

    #region FFT
    bool newRange = false;
    if(graphFFT.MaxY != d.fftRangeYMax) {
      graphFFT.MaxY = d.fftRangeYMax;
      newRange = true;
    }
    if(graphFFT.MinY != d.fftRangeYMin) {
      graphFFT.MinY = d.fftRangeYMin;
      newRange = true;
    }

    int tempLength = 0;
    short[] tempData;

    int i = 0;

    lock(d.fftDataLock) {
      tempLength = d.fftLength;
      tempData = (short[])d.fftData.Clone();
    }

    graphFFT.SetLine("FFT", tempData);

    if(newRange) graphFFT.RefreshGraphComplete();
    else if(PanelFFT.Visible) graphFFT.RefreshGraph();
    #endregion

    // End of your code

    tim.Enabled = true; // Drawing is done, allow new frames to come in.
  }
}

Here's the optimized SetLine() which no longer takes a list of points but the raw data: 这是优化的SetLine(),它不再采用点列表,而是原始数据:

public class GraphFFT {
    public void SetLine(String lineTitle, short[] values) {
      IPointListEdit ip = zgcGraph.GraphPane.CurveList[lineTitle].Points as IPointListEdit;
      int tmp = Math.Min(ip.Count, values.Length);
      int i = 0;
      peakX = values.Length;

      while(i < tmp) {
        if(values[i] > peakY) peakY = values[i];
        ip[i].X = i;
        ip[i].Y = values[i];
        i++;
      }
      while(ip.Count < values.Count) {
        if(values[i] > peakY) peakY = values[i];
        ip.Add(i, values[i]);
        i++;
      }
      while(values.Count > ip.Count) {
        ip.RemoveAt(ip.Count - 1);
      }
    }
  }

I hope you get that working, as I commented before, I hav'nt got the chance to compile or check it so there could be some bugs there. 我希望你能够正常工作,正如我之前评论过的那样,我没有机会编译或检查它,因此可能存在一些错误。 There's more to be optimized there, but the optimizations should be marginal compared to the boost of skipping frames and only collecting data when we have the time to actually draw the frame before the next one comes in. 还有更多要优化的地方,但与跳过帧的增强相比,优化应该是边际的,并且只有在我们有时间在下一个帧进入之前实际绘制帧时才收集数据。

If you closely study the graphs in the video at iZotope , you'll notice that they too are skipping frames, and sometimes are a bit jumpy. 如果您仔细研究iZotope视频中的图形,您会发现它们也在跳帧,有时候会有些跳跃。 That's not bad at all, it's a trade-off you make between the processing power of the foreground thread and the background workers. 这一点都不错,这是你在前台线程的处理能力和后台工作者之间做出的权衡。

If you really want the drawing to be done in a separate thread, you'll have to draw the graph to a bitmap (calling Draw() and passing the bitmaps device context). 如果您真的希望绘图在单独的线程中完成,则必须将图形绘制到位图(调用Draw()并传递位图设备上下文)。 Then pass the bitmap on to the main thread and have it update. 然后将位图传递给主线程并让它更新。 That way you do lose the convenience of the designer and property grid in your IDE, but you can make use of otherwise vacant processor cores. 这样,您确实会失去IDE中设计器和属性网格的便利性,但您可以利用其他空置的处理器内核。

---------- edit answer to remarks -------- ----------编辑答案备注--------

Yes there is a way to tell what calls what. 是的,有一种方法可以说出什么叫什么。 Look at your first screen-shot, you have selected the "call tree" graph. 看看你的第一个屏幕截图,你已经选择了“调用树”图。 Each next line jumps in a bit (it's a tree-view, not just a list!). 每个下一行都跳了一下(这是一个树视图,而不仅仅是一个列表!)。 In a call-graph, each tree-node represents a method that has been called by its parent tree-node (method). 在调用图中,每个树节点表示由其父树节点(方法)调用的方法。

In the first image, WndProc was called about 1800 times, it handled 872 messages of which 62 triggered ZedGraphControl.OnPaint() (which in turn accounts for 53% of the main threads total time). 在第一张图片中, WndProc被调用了大约1800次,它处理了872条消息,其中62条消息触发了ZedGraphControl.OnPaint() (后者占主线程总时间的53%)。

The reason you don't see another rootnode, is because the 3rd dropdown box has selected "[604] Mian Thread" which I didn't notice before. 你没有看到另一个rootnode的原因是因为第3个下拉框选择了“[604] Mian Thread”,我之前没有注意到。

As for the more fluent graphs, I have 2nd thoughts on that now after looking more closely to the screen-shots. 至于更流畅的图表,在仔细观察屏幕截图后,我对此有了第二个想法。 The main thread has clearly received more (double) update messages, and the CPU still has some headroom. 主线程明显收到更多(双)更新消息,CPU仍有一些空间。

It looks like the threads are out-of-sync and in-sync at different times, where the update messages arrive just too late (when WndProc was done and went to sleep for a while), and then suddenly in time for a while. 看起来线程在不同的时间是不同步和同步的,更新消息到达的时间太晚(当WndProc完成并进入睡眠状态一段时间),然后突然及时一段时间。 I'm not very familiar with Ants, but does it have a side-by side thread timeline including sleep time? 我对蚂蚁不是很熟悉,但是它有一个并排的线程时间表,包括睡眠时间吗? You should be able to see what's going on in such a view. 你应该能够看到这种观点中发生了什么。 Microsofts threads view tool would come in handy for this: 微软线程视图工具将派上用场: 在此输入图像描述

Luaan posted the solution in the comments above, it's the system wide timer resolution. Luaan在上面的评论中发布了解决方案,它是系统范围的计时器分辨率。 Default resolution is 15.6 ms, the profiler sets the resolution to 1ms. 默认分辨率为15.6 ms,探查器将分辨率设置为1ms。

I had the exact same problem, very slow execution that would speed up when the profiler was opened. 我有完全相同的问题,执行速度非常慢,在打开探查器时速度会加快。 The problem went away on my PC but popped back up on other PCs seemingly at random. 问题在我的电脑上消失了,但似乎随机地重新出现在其他电脑上。 We also noticed the problem disappeared when running a Join Me window in Chrome. 我们还注意到在Chrome中运行Join Me窗口时问题消失了。

My application transmits a file over a CAN bus. 我的应用程序通过CAN总线传输文件。 The app loads a CAN message with eight bytes of data, transmits it and waits for an acknowledgment. 该应用程序加载带有8个字节数据的CAN消息,发送它并等待确认。 With the timer set to 15.6ms each round trip took exactly 15.6ms and the entire file transfer would take about 14 minutes. 定时器设置为15.6ms,每次往返只需15.6ms,整个文件传输大约需要14分钟。 With the timer set to 1ms round trip time varied but would be as low as 4ms and the entire transfer time would drop to less than two minutes. 定时器设置为1ms,往返时间变化但会低至4ms,整个传输时间将降至不到两分钟。

You can verify your system timer resolution as well as find out which program increased the resolution by opening a command prompt as administrator and entering: 您可以通过以管理员身份打开命令提示符并输入以下命令来验证系统计时器分辨率以及找出哪个程序提高了分辨率:

powercfg -energy duration 5

The output file will have the following in it somewhere: 输出文件将在其中包含以下内容:

Platform Timer Resolution:Platform Timer Resolution The default platform timer resolution is 15.6ms (15625000ns) and should be used whenever the system is idle. 平台定时器分辨率:平台定时器分辨率默认平台定时器分辨率为15.6ms(15625000ns),应在系统空闲时使用。 If the timer resolution is increased, processor power management technologies may not be effective. 如果定时器分辨率增加,则处理器电源管理技术可能无效。 The timer resolution may be increased due to multimedia playback or graphical animations. 由于多媒体回放或图形动画,可以增加定时器分辨率。 Current Timer Resolution (100ns units) 10000 Maximum Timer Period (100ns units) 156001 电流定时器分辨率(100ns单位)10000最大定时器周期(100ns单位)156001

My current resolution is 1 ms (10,000 units of 100nS) and is followed by a list of the programs that requested the increased resolution. 我当前的分辨率是1毫秒(10,000单位100nS),然后是一个请求提高分辨率的程序列表。

This information as well as more detail can be found here: https://randomascii.wordpress.com/2013/07/08/windows-timer-resolution-megawatts-wasted/ 此信息以及更多详细信息可在此处找到: https//randomascii.wordpress.com/2013/07/08/windows-timer-resolution-megawatts-wasted/

Here is some code to increase the timer resolution (originally posted as the answer to this question: how to set timer resolution from C# to 1 ms? ): 下面是一些增加定时器分辨率的代码(最初发布为这个问题的答案: 如何将定时器分辨率从C#设置为1毫秒? ):

public static class WinApi
{
    /// <summary>TimeBeginPeriod(). See the Windows API documentation for details.</summary>

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Interoperability", "CA1401:PInvokesShouldNotBeVisible"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2118:ReviewSuppressUnmanagedCodeSecurityUsage"), SuppressUnmanagedCodeSecurity]
    [DllImport("winmm.dll", EntryPoint = "timeBeginPeriod", SetLastError = true)]

    public static extern uint TimeBeginPeriod(uint uMilliseconds);

    /// <summary>TimeEndPeriod(). See the Windows API documentation for details.</summary>

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Interoperability", "CA1401:PInvokesShouldNotBeVisible"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2118:ReviewSuppressUnmanagedCodeSecurityUsage"), SuppressUnmanagedCodeSecurity]
    [DllImport("winmm.dll", EntryPoint = "timeEndPeriod", SetLastError = true)]

    public static extern uint TimeEndPeriod(uint uMilliseconds);
}

Use it like this to increase resolution : WinApi.TimeBeginPeriod(1); 像这样使用它来提高分辨率: WinApi.TimeBeginPeriod(1);

And like this to return to the default : WinApi.TimeEndPeriod(1); 并且像这样返回默认值: WinApi.TimeEndPeriod(1);

The parameter passed to TimeEndPeriod() must match the parameter that was passed to TimeBeginPeriod(). 传递给TimeEndPeriod()的参数必须与传递给TimeBeginPeriod()的参数匹配。

When I have never heard or seen something similar; 当我从未听过或看到类似的东西时; I'd recommend the common sense approach of commenting out sections of code/injecting returns at tops of functions until you find the logic that's producing the side effect. 我建议使用常识方法来注释代码部分/在函数顶部注入返回,直到找到产生副作用的逻辑。 You know your code and likely have an educated guess where to start chopping. 你知道你的代码,可能有一个有根据的猜测从哪里开始砍。 Else chop mostly all as a sanity test and start adding blocks back. 其他大部分都是作为一个完整性测试并开始添加块。 I'm often amazed how fast one can find those seemingly impossible bugs to track. 我常常惊讶于人们能够找到那些看似不可能跟踪的错误。 Once you find the related code, you will have more clues to solve your issue. 找到相关代码后,您将获得更多解决问题的线索。

If you have a method which throws a lot of exceptions, it can run slowly in debug mode and fast in CPU Profiling mode. 如果你有一个抛出很多异常的方法,它可以在调试模式下运行缓慢,在CPU分析模式下运行速度很快。

As detailed here , debug performance can be improved by using the DebuggerNonUserCode attribute. 详见这里 ,调试性能可以通过使用来提高DebuggerNonUserCode属性。 For example: 例如:

[DebuggerNonUserCode]
public static bool IsArchive(string filename)
{
    bool result = false;
    try
    {
        //this calls an external library, which throws an exception if the file is not an archive
        result = ExternalLibrary.IsArchive(filename);
    }
    catch
    {

    }
    return result;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM