在C#中优化代码是否存在风险?

时间:2011-12-11 20:07:36

标签: c# .net optimization compiler-construction settings

在VS2010 Pro的构建设置面板中,有一个带有“优化代码”标签的CheckBox ......当然,我想检查一下......但是要非常小心,我问我的兄弟,他和他说它没有被调试用于调试,而且在C ++中它可能会做一些破坏或破坏代码的事情......但他不知道C#。

所以我的问题是,我可以在此框中查看我的发布版本,而不必担心它会破坏我的代码吗?第二,如果它可以破解代码,何时以及为什么?链接到解释欢迎。

The CheckBox I am talking about.

8 个答案:

答案 0 :(得分:25)

您通常会在发布版本中使用此选项。这样做是安全和主流的。没有理由害怕在启用优化的情况下发布代码。启用优化可能会干扰调试,这是禁用调试版本的一个很好的理由。

答案 1 :(得分:16)

优化不应该真正破坏您的代码。 Eric Lippert有一个post here,它解释了当你打开那个标志时会发生什么。性能增益因应用程序而异,因此您需要使用项目对其进行测试,以确定是否存在任何明显的差异(就性能而言)。

答案 2 :(得分:7)

在发布模式下运行时可能会发生一些错误,否则会发生错误。脑海中浮现出臭名昭着的“非挥发性旗帜”:

flag = false;

Thread t = new Thread(
   o =>
   {
        while(!flag)
        {
           // do stuff
        }
   });
t.Start();

// main thread does some work

flag = true;
t.Join(); // will never return in release mode if flag is not volatile

这是因为编译器优化,因为标志变量被线程t的核心缓存,因此它无法看到标志的更新值。

答案 3 :(得分:3)

优化应该引入错误吗?否。

优化会引入错误吗?也许,毕竟没有什么是完美的。

操作系统是否可以发现代码中始终存在的错误,但在关闭时会隐藏错误?绝对地,发生了很多。

重要的是要意识到这是一个变化。就像你测试你是否做了很多改变一样,你应该测试你何时关闭它们。如果最终版本打开它们,那么最终测试也必须打开它们。

答案 4 :(得分:1)

在C#中,优化不应该破坏你的代码。

相反,在启用优化的情况下,编译器在C#和CIL之间进行转换时会产生更紧凑的CIL。

我观察到(并且坦率地说这很有趣!)来自.NET的C#编译器< 2.0(1.0和1.1)产生良好的CIL,没有优化,因为后来的C#编译器(2.0及更高版本)产生了WITH优化。

答案 5 :(得分:1)

示例明智我有一段代码来自我的硕士论文的一些模拟部分。在打开优化标志的情况下,代码并没有真正破坏程序,但路径查找器只执行一次运行和循环。 (递归代码将自身陷入路径查找器的循环中,它始终在关闭优化标志的情况下突破)。

所以是的,优化标志有可能使软件的行为不同。

答案 6 :(得分:0)

.net编译器优化可能会导致错误。今天发生在我身上。我花了几个小时来钉它。代码是:

for (int i = 0; i < list.Count-1; i++) {
  list[i+1].DoSomeThing();
  //some code
  if (someCondition) {
    list.insert(i+1, new Item());
    i++;
  }
}

在某些时候,list[i+1]被称为list[i],就好像两者都指向同一个项目一样。 这个bug真是太奇怪了。代码在调试模式和发布模式下运行良好,但是当我把它运行到侧面视觉工作室时,例如。从.exe文件中,代码崩溃了。只关闭编译器优化修复它。

答案 7 :(得分:0)

在我的情况下,当我打开优化标记时,它无法完成所有操作,因此最终结果中缺少测量点,因此我只是关闭了优化标记以修复错误:

using System.Threading.Tasks;

                Parallel.Invoke(
                    async () => await ProcessPartialArrayOperationAssets(operationAssets, 0, operationAssets.Count / 2,
                        operations, inspection1),
                    async () => await ProcessPartialArrayOperationAssets(operationAssets, operationAssets.Count / 2,
                        operationAssets.Count, operations, inspection1)
                );

private async Task ProcessPartialArrayInspectionOperations(IList<InspectionOperation> operations,
    int begin,
    int end,
    Inspection inspection,
    InspectionAsset inspectionAsset)
{
    await Task.Run(() =>
    {
        // create one new operation measuring point for each measuring point in the operation's equipment
        int itemCounter = begin + 1;

        for (int i = begin; i < end; i++)
        {
            lock (_thisLock)
            {
                InspectionOperation operation = operations[i];
                int itemNumber = 1;

                // get the asset
                InspectionAsset operationAsset = operation.OperationAsset;
                if (operationAsset != null)
                {
                    // get the measuring points
                    string ABAPTrue = Abap.ABAP_TRUE;

                    lock (_thisLock)
                    {
                        IList<MeasuringPoint> measuringPoints = DbContext.MeasuringPoints.Where(x =>
                                x.AssetID == operationAsset.AssetID && x.InactiveFlag != ABAPTrue)
                            .ToList();

                        if (measuringPoints != null)
                        {
                            //Debug.WriteLine("measuringPoints.Count = " + measuringPoints.Count);

                            // create the operation measuring points
                            foreach (MeasuringPoint measuringPoint in measuringPoints)
                            {
                                OperationMeasuringPoint operationMeasuringPoint =
                                    new OperationMeasuringPoint
                                    {
                                        InspectionID = inspection.InspectionID,
                                        OperationNumber = operation.OperationNumber,
                                        SubActivity = "",
                                        RoutingNo = "",
                                        ItemNumber = itemNumber.ToString("D4"),
                                        // e.g. "0001", "0002" and so on
                                        ItemCounter = itemCounter.ToString("D8"),
                                        // e.g. "00000001", "00000002" and so on
                                        MeasuringPointID = measuringPoint.MeasuringPointID,
                                        MeasuringPointDescription = measuringPoint.Description,
                                        Equipment = inspectionAsset.AssetID,
                                        Category = "P"
                                    };
                                DbContext.Entry(operationMeasuringPoint).State = EntityState.Added;
                                itemNumber++;
                                itemCounter++;
                            }
                        }
                    }
                }
            }
        }
    });
}

因此,我也以此替换了Parallel.Invoke调用。仅供参考,此问题是使用.NET Framework 4.7发生的。

await ProcessPartialArrayOperationAssets(operationAssets, 0, operationAssets.Count, operations, inspection1);

更新:

好的,我发现如果我从方法签名中删除了Parallel.Invoke,我就能重新启用优化标志并使用async Task

    private void ProcessPartialArrayInspectionOperations(IList<InspectionOperation> operations,
        int begin,
        int end,
        Inspection inspection,
        InspectionAsset inspectionAsset)
    {
        // create one new operation measuring point for each measuring point in the operation's equipment
        int itemCounter = begin + 1;

        for (int i = begin; i < end; i++)
        {

            InspectionOperation operation = operations[i];
            int itemNumber = 1;

            // get the asset
            InspectionAsset operationAsset = operation.OperationAsset;
            if (operationAsset != null)
            {
                // get the measuring points
                string ABAPTrue = Abap.ABAP_TRUE;

                lock (_thisLock)
                {
                    IList<MeasuringPoint> measuringPoints = DbContext.MeasuringPoints.Where(x =>
                            x.AssetID == operationAsset.AssetID && x.InactiveFlag != ABAPTrue)
                        .ToList();

                    if (measuringPoints != null)
                    {
                        //Debug.WriteLine("measuringPoints.Count = " + measuringPoints.Count);

                        // create the operation measuring points
                        foreach (MeasuringPoint measuringPoint in measuringPoints)
                        {
                            OperationMeasuringPoint operationMeasuringPoint =
                                new OperationMeasuringPoint
                                {
                                    InspectionID = inspection.InspectionID,
                                    OperationNumber = operation.OperationNumber,
                                    SubActivity = "",
                                    RoutingNo = "",
                                    ItemNumber = itemNumber.ToString("D4"),
                                    // e.g. "0001", "0002" and so on
                                    ItemCounter = itemCounter.ToString("D8"),
                                    // e.g. "00000001", "00000002" and so on
                                    MeasuringPointID = measuringPoint.MeasuringPointID,
                                    MeasuringPointDescription = measuringPoint.Description,
                                    Equipment = inspectionAsset.AssetID,
                                    Category = "P"
                                };
                            DbContext.Entry(operationMeasuringPoint).State = EntityState.Added;
                            itemNumber++;
                            itemCounter++;
                        }
                    }
                }
            }
        }
    }

                        Parallel.Invoke(
                            () => ProcessPartialArrayInspectionOperations(operations, 0, operations.Count / 2,
                                inspection1, inspectionAsset),
                            () => ProcessPartialArrayInspectionOperations(operations, operations.Count / 2,
                                operations.Count, inspection1, inspectionAsset)
                        );

或者,我认为我可以分别使用Task.Run然后等待Task.WhenAll(t1, t2, t3);,如此处所述,但是在这种情况下,我没有进行显式的数据库调用,因此我认为它不适用于使用Task.Run而不是Parallel.Invoke,尽管此页面确实解释了为什么我的Parallel.Invoke无法完成:Parallel.Invoke does not wait for async methods to complete

有关详细信息,请参见“ C#中的并发性” https://stephencleary.com/book/