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)
如果我反复使用整个列表,那就太好了,但不是那么好.
是否存在中间点,我可以在整个列表被迭代之前返回,然后缓存它并将缓存提供给后续请求?
最终编辑:
我选择了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) [编辑]
新的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()时将项添加到缓存中.以下是我目前的实施: …
我有一个关于效率Skip()和Take()使用时间的问题IEnumerable<>.
我正在返回我的所有数据列表,IEnumerable<>并使用'yield return'来防止我必须分配大量内存来传回数据.这非常有效.
但是,稍后在我的过程中,我想批量处理这些数据,并一次从我的列表中删除20个条目.我心想啊..啊!这非常适合普查员.
我发现非常有用Skip(),并Take()在方法IEnumerable interface不过我现在意识到这导致我的循环每次重新interate从此开始.
从一个页面分页数据的最佳方法是IEnumerable什么?我最好不要使用MoveFirst()和使用MoveNext()枚举器而不是Skip()和Take()?
我做了一些谷歌搜索,但找不到答案..
有人可以帮忙吗?
我真的很喜欢LINQ功能,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)
我想准备对其他函数的输入,以便:
ToList()或ToArray()它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# ×5
ienumerable ×3
linq ×3
performance ×3
.net ×1
caching ×1
enumerable ×1
return ×1
yield ×1