我正在做一些关于 yield 返回性能的测试,我发现它比正常返回慢。
我测试了值变量(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);
}
}
最佳答案
考虑 File.ReadAllLines
和 File.ReadLines
之间的区别。
ReadAllLines
将所有行加载到内存中并返回一个 string[]
。如果文件很小,一切都很好。如果文件大于内存中的容量,您将耗尽内存。
ReadLines
使用 yield return
一次返回一行。有了它,您可以读取任何大小的文件。它不会将整个文件加载到内存中。
假设您想找到包含单词“foo”的第一行,然后退出。使用 ReadAllLines
,您必须将整个文件读入内存,即使“foo”出现在第一行也是如此。使用 ReadLines
,您只需阅读一行。哪个会更快?
这不是唯一的原因。考虑一个读取文件并处理每一行的程序。使用 File.ReadAllLines
,您最终得到:
string[] lines = File.ReadAllLines(filename);
for (int i = 0; i < lines.Length; ++i)
{
// process line
}
程序执行的时间等于读取文件的时间加上处理行的时间。想象一下,处理需要很长时间,以至于您想使用多个线程来加快处理速度。所以你做这样的事情:
lines = File.ReadAllLines(filename);
Parallel.Foreach(...);
但是读取是单线程的。在主线程加载整个文件之前,您的多个线程无法启动。
不过,使用 ReadLines
,您可以执行以下操作:
Parallel.Foreach(File.ReadLines(filename), line => { ProcessLine(line); });
这会立即启动多个线程,这些线程在读取其他行的同时进行处理。因此读取时间与处理时间重叠,这意味着您的程序将执行得更快。
我使用文件展示我的示例,因为这样更容易演示概念,但内存中的集合也是如此。使用 yield return
将使用更少的内存并且可能更快,尤其是在调用只需要查看部分集合的方法时(Enumerable.Any
、Enumerable.首先
等)。
关于c# - 'yield return' 比 "old school"返回慢吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18145944/