特定场景下Dotnet应用程序中Debug和Release模式的区别

问题描述 投票:0回答:2

我正在阅读 .NET 中的异步编程

其中提到了使用线程的简单程序的调试和发布模式。

考虑以下代码:

internal class Program
{
    static void Main(string[] args)
    {
         AsyncTest objAsyncTest = new AsyncTest();
   
         while(!objAsyncTest.isTerminate);
    }
}
 

public class AsyncTest
{
    public bool isTerminate { get; set; }
    
    public AsyncTest()
    {
        Thread monitorThread = new Thread(MoniterThread);
        monitorThread.Start();
    }
    
    public void MoniterThread()
    {
         Thread.Sleep(3000);
         isTerminate = true;
    }
}

因此,如果我在调试模式下运行上面的程序,它将在三秒内停止。

但是如果我在发布模式下运行相同的程序。它永远不会出来,也不会停止。

如果有人可以向我解释为什么会这样,将会非常有帮助。

c# .net multithreading asynchronous console-application
2个回答
0
投票

调试模式:

符号: 调试模式包括带有编译代码的符号(调试信息)。这些符号通过提供附加信息(例如变量名称、行号等)在调试会话期间提供帮助。 优化: 调试模式通常会禁用大多数优化,从而更容易调试代码。这意味着编译后的代码可能运行速度较慢,但提供了更好的调试体验。 无代码优化: 代码未针对调试模式下的性能进行优化,因此在内存使用和执行速度方面可能效率较低。 断言: 断言和断言相关代码(例如 Debug.Assert)通常包含在调试模式下并在调试模式下执行,有助于识别开发过程中的逻辑错误。 记录: 开发人员可能会在调试模式下添加额外的日志记录或诊断功能,以帮助在开发过程中进行故障排除和监控。

发布方式:

无符号: 发布模式会省略编译代码中的符号,从而减小可执行文件的大小并使逆向工程变得更加困难。 启用优化: 发布模式可以实现各种编译器优化,以提高代码的性能和效率。这些优化可以包括内联函数、删除无法访问的代码以及优化内存使用。 无断言: 断言和相关调试代码通常在发布模式下被删除或禁用,以提高运行时性能。 记录和诊断代码: 仅在开发或调试期间需要的日志记录和诊断功能可以在发布模式下删除或禁用,以减少开销。 绩效重点: 发布模式针对性能和效率进行了优化,使其适合在速度和资源使用至关重要的生产环境中部署。


0
投票

相关的区别在于,在发布版本中启用了优化

其中一个有效的优化是让主线程假设这一行:

while(!objAsyncTest.isTerminate);

isTerminate
实际上永远不会改变(因为当前线程中没有这种可见的变化),因此循环变成无限循环,因为
isTerminate
实际上只会被[可能]检查一次。

一种解决方案是使用

volatile
字段:

volatile 关键字表示字段可能会被修改 同时执行的多个线程。编译器, 运行时系统,甚至硬件可能会重新安排读取和写入 出于性能原因到内存位置。 声明的字段 易失性被排除在某些类型的优化之外。

(重点是我的)

您的情况:

//------vvvvvvvv--------------------------
private volatile bool isTerminate_ = false;

public bool isTerminate 
{ 
     get { return isTerminate_; } 
     set { isTerminate_ = value; } 
}

使其

volatile
意味着编译器必须考虑到该字段可能会被另一个线程修改,并在每次迭代中实际检查它的值。

旁注:
使用紧密循环来检查字段是否已修改(如

while(!objAsyncTest.isTerminate);
)并不是一个好的做法,因为它会使主线程无缘无故地消耗大量 CPU 时间。

© www.soinside.com 2019 - 2024. All rights reserved.