c# - 'yield return' 比 "old school"返回慢吗?

标签 c# yield-return

我正在做一些关于 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.ReadAllLinesFile.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.AnyEnumerable.首先等)。

关于c# - 'yield return' 比 "old school"返回慢吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18145944/

相关文章:

c# - 遍历数据中继器中所有行的最佳方法?

c# - 存储库模式和/或/与业务逻辑层

c# - 将 WCF 服务放入文件夹会抛出 404

c# - 使用嵌套方法时奇怪的执行顺序,yield return 和组合使用

c# - 为什么 Visual Studio 认为我的 "yield return"方法返回动态对象?

c# - 使用 yield 和 foreach 迭代自定义对象集合,无需装箱/拆箱

c# - 在 .net Core WebApi 中从 startup.cs 访问 HttpContextAccessor

c# - 使用 C# 检索 Active Directory 组中的所有用户

c# - yield 返回和异常处理

c# - 如何避免 Iterator 方法被重启?