在VS2010 Pro的构建设置面板中,有一个带有“优化代码”标签的CheckBox ......当然,我想检查一下......但是要非常小心,我问我的兄弟,他和他说它没有被调试用于调试,而且在C ++中它可能会做一些破坏或破坏代码的事情......但他不知道C#。
所以我的问题是,我可以在此框中查看我的发布版本,而不必担心它会破坏我的代码吗?第二,如果它可以破解代码,何时以及为什么?链接到解释欢迎。
答案 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/