我正在进行关于 yield return 性能的测试,发现它比普通的 return 操作慢。
我测试了值类型变量(int、double 等)和一些引用类型(string 等),发现在两种情况下使用 yield return 都比较慢。那么为什么还要使用它呢?
看看我的例子:
public class YieldReturnTeste
{
private static IEnumerable<string> YieldReturnTest(int limite)
{
for (int i = 0; i < limite; i++)
{
yield return i.ToString();
}
}
private static IEnumerable<string> NormalReturnTest(int limite)
{
List<string> listaInteiros = new List<string>();
for (int i = 0; i < limite; i++)
{
listaInteiros.Add(i.ToString());
}
return listaInteiros;
}
public static void executaTeste()
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
List<string> minhaListaYield = YieldReturnTest(2000000).ToList();
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
ts.Hours, ts.Minutes, ts.Seconds,
ts.Milliseconds / 10);
Console.WriteLine("Yield return: {0}", elapsedTime);
//****
stopWatch = new Stopwatch();
stopWatch.Start();
List<string> minhaListaNormal = NormalReturnTest(2000000).ToList();
stopWatch.Stop();
ts = stopWatch.Elapsed;
elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
ts.Hours, ts.Minutes, ts.Seconds,
ts.Milliseconds / 10);
Console.WriteLine("Normal return: {0}", elapsedTime);
}
}
NormalReturnTest
应该将其列表长度预初始化为limite
。其次,我相当确定当在List
上操作.ToList()
方法时,它会对其基础数组进行特殊检查,并执行数组复制,而不是迭代列表并逐个复制项目,从而产生完全不同的结果。而你的yield return
可枚举对象上的.ToList()
将不得不迭代每个元素并构建数组(沿途导致多次调整大小以达到 2000000 个元素)。你正在测量错误的东西。 - Chris Sinclairforeach
循环中吗?因为如果你不迭代它,yield return
实际上就什么也不会做。 - Chris Sinclairyield return
调用时执行,仅当在迭代期间调用MoveNext
方法时才会执行。 - Chris Sinclair