相关疑难解决方法(0)

缓存IEnumerable

public IEnumerable<ModuleData> ListModules()
{
    foreach (XElement m in Source.Descendants("Module"))
    {
        yield return new ModuleData(m.Element("ModuleID").Value);
    }
}
Run Code Online (Sandbox Code Playgroud)

最初上面的代码很棒,因为如果不需要,就不需要评估整个集合.

但是,一旦枚举了所有模块,在没有更改时重复查询XDocument会变得更加昂贵.

因此,作为绩效改进:

public IEnumerable<ModuleData> ListModules()
{
    if (Modules == null)
    {
        Modules = new List<ModuleData>();
        foreach (XElement m in Source.Descendants("Module"))
        {
            Modules.Add(new ModuleData(m.Element("ModuleID").Value, 1, 1));
        }
    }
    return Modules;
}
Run Code Online (Sandbox Code Playgroud)

如果我反复使用整个列表,那就太好了,但不是那么好.

是否存在中间点,我可以在整个列表被迭代之前返回,然后缓存它并将缓存提供给后续请求?

c# ienumerable yield return

19
推荐指数
5
解决办法
4666
查看次数

缓冲LINQ查询

最终编辑:

我选择了Timothy的答案,但如果你想要一个利用C#yield语句的可行实现,请检查Eamon的答案:https://stackoverflow.com/a/19825659/145757


默认情况下,LINQ查询是延迟流式传输的.

ToArray/ ToList给予完全缓冲,但首先他们渴望,其次可能需要相当长的时间来完成无限序列.

有没有办法将这两种行为结合起来:生成时动态流式传输缓冲值,以便下一次查询不会触发已经查询过的元素的生成.

这是一个基本用例:

static IEnumerable<int> Numbers
{
    get
    {
        int i = -1;

        while (true)
        {
            Console.WriteLine("Generating {0}.", i + 1);
            yield return ++i;
        }
    }
}

static void Main(string[] args)
{
    IEnumerable<int> evenNumbers = Numbers.Where(i => i % 2 == 0);

    foreach (int n in evenNumbers)
    {
        Console.WriteLine("Reading {0}.", n);
        if …
Run Code Online (Sandbox Code Playgroud)

.net c# linq ienumerable

19
推荐指数
4
解决办法
2687
查看次数

有关缓存的IEnumerable <T>实现的性能

[编辑]

新的Reactive Framework使用System.Linq.EnumerableEx.MemoizeAll()扩展方法解决了下面列出的问题.

在内部,MemoizeAll()使用a System.Linq.EnumerableEx.MemoizeAllEnumerable<T>(在System.Interactive程序集中找到),类似于my ThreadSafeCachedEnumerable<T>(sorta).

这是一个非常人为的例子,它非常缓慢地打印出Enumerable(数字1-10)的内容,然后第二次快速打印内容(因为它缓存了值):

// Create an Enumerable<int> containing numbers 1-10, using Thread.Sleep() to simulate work
var slowEnum = EnumerableEx.Generate(1, currentNum => (currentNum <= 10), currentNum => currentNum, previousNum => { Thread.Sleep(250); return previousNum + 1; });

// This decorates the slow enumerable with one that will cache each value.
var cachedEnum = slowEnum.MemoizeAll();

// Print the numbers
foreach (var num in cachedEnum.Repeat(2))
{
    Console.WriteLine(num);
}
Run Code Online (Sandbox Code Playgroud)

[/编辑]

你好多线程大师,

我创建了ThreadSafeCachedEnumerable类,旨在提高长时间运行的重用查询的性能.我们的想法是从IEnumerable获取一个枚举器,并在每次调用MoveNext()时将项添加到缓存中.以下是我目前的实施: …

c# performance ienumerable multithreading caching

4
推荐指数
1
解决办法
2022
查看次数

LINQ/IEnumerable Skip().Take()效率与"yield return"一起使用

我有一个关于效率Skip()Take()使用时间的问题IEnumerable<>.

我正在返回我的所有数据列表,IEnumerable<>并使用'yield return'来防止我必须分配大量内存来传回数据.这非常有效.

但是,稍后在我的过程中,我想批量处理这些数据,并一次从我的列表中删除20个条目.我心想啊..啊!这非常适合普查员.

我发现非常有用Skip(),并Take()在方法IEnumerable interface不过我现在意识到这导致我的循环每次重新interate从此开始.

从一个页面分页数据的最佳方法是IEnumerable什么?我最好不要使用MoveFirst()和使用MoveNext()枚举器而不是Skip()Take()

我做了一些谷歌搜索,但找不到答案..

有人可以帮忙吗?

我真的很喜欢LINQ功能,IEnumerable<>但我必须考虑效率.

c# linq performance enumerable

4
推荐指数
2
解决办法
2542
查看次数

昂贵的 IEnumerable:有什么方法可以防止多次枚举而不强制立即枚举?

我有一个非常大的枚举,并且正在准备对其进行昂贵的延迟操作(例如对其进行排序)。然后,我将其传递给一个函数,该函数可能会也可能不会消耗 IEnumerable,具体取决于其自身的某些逻辑。

这是一个例子:

IEnumerable<Order> expensiveEnumerable = fullCatalog.OrderBy(c => Prioritize(c));
MaybeFullFillSomeOrders(expensiveEnumerable);

// Elsewhere... (example use-case for multiple enumerations, not real code)
void MaybeFullFillSomeOrders(IEnumerable<Order> nextUpOrders){
    if(notAGoodTime())
       return;
    foreach(var order in nextUpOrders)
       collectSomeInfo(order);
    processInfo();
    foreach(var order in nextUpOrders) {
       maybeFulfill(order);
       if(atCapacity())
          break;
    }
}
Run Code Online (Sandbox Code Playgroud)

我想准备对其他函数的输入,以便:

  1. 如果它们不消耗可枚举值,则不会付出排序的性能代价。
    • 这已经阻止了调用例如ToList()ToArray()
  2. 如果他们选择多次枚举(也许没有意识到在这种情况下会有多昂贵),我希望采取一些防御措施来防止多次枚举。
  3. 理想情况下,结果仍然是IEnumerable<T>

我想出的最好的解决方案是使用Lazy<>

var expensive = new Lazy<List<Order>>>(
    () => fullCatalog.OrderBy(c => Prioritize(c)).ToList());
Run Code Online (Sandbox Code Playgroud)

这似乎满足标准 1 和 2,但有一些缺点:

  • 我必须更改所有下游用途的接口才能期望Lazy.
  • 完整列表(在本例中是由多个较小的分区构建的SelectMany())需要在内存中分配为新的单个连续列表。如果我想“缓存”排序结果,我不确定是否有一种简单的方法可以解决这个问题,但如果你知道有一种方法,我会洗耳恭听。

我必须解决第一个问题的一个想法是包装Lazy<>一些自定义类,该类可以实现或可以隐式转换为IEnumerable<T>,但我希望有人知道一种更优雅的方法。

c# linq performance

4
推荐指数
1
解决办法
389
查看次数