.NET 8 在适用的 Enumerable.Sum 方法中添加了对矢量化的支持。 此更改会有一个附带影响,即矢量化实现可能会更改添加不同元素时采用的顺序。 虽然这不会改变成功运行的最终结果,但它可能会导致某些病理输入集出现意外的 OverflowException 异常。
旧行为
考虑下列代码:
Test(GetEnumerable1()); // Non-vectorizable
Test(GetEnumerable1().ToArray()); // Vectorizable
Test(GetEnumerable2()); // Non-vectorizable
Test(GetEnumerable2().ToArray()); // Vectorizable
static IEnumerable<int> GetEnumerable1()
{
for (int i = 0; i < 32; ++i)
{
yield return 1_000_000_000;
yield return -1_000_000_000;
}
}
static IEnumerable<int> GetEnumerable2()
{
for (int i = 0; i < 32; ++i)
{
yield return 100_000_000;
}
for (int i = 0; i < 32; ++i)
{
yield return -100_000_000;
}
}
static void Test(IEnumerable<int> input)
{
try
{
Console.WriteLine(input.Sum());
}
catch (Exception ex)
{
Console.WriteLine(ex.GetType().Name);
}
}
在进行此更改之前,前面的代码生成了以下输出:
0
0
OverflowException
OverflowException
新行为
从 .NET 8 开始,旧行为部分中的代码片段会生成以下输出:
0
OverflowException
OverflowException
0
引入的版本
.NET 8 预览版 7
中断性变更的类型
此更改为行为更改。
更改原因
此更改旨在利用 LINQ API 中的向量化。
建议的操作
如果代码受更改影响,则可以:
通过将
DOTNET_EnableHWIntrinsic
环境变量设置为 0,在应用程序中完全禁用矢量化。编写不使用矢量化的自定义
Sum
方法:static int Sum(IEnumerable<int> values) { int acc = 0; foreach (int value in values) { checked { acc += value; } } return acc; }