.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_EnableHWIntrinsic0,在应用程序中完全禁用矢量化。编写不使用矢量化的自定义
Sum方法:static int Sum(IEnumerable<int> values) { int acc = 0; foreach (int value in values) { checked { acc += value; } } return acc; }