我问了一个问题并得到了here关于性能问题的回答,这些问题与大型数据集合有关。 (用linq创建)
好吧,让我们把它放在一边。但是Marc建议的一个有趣的(和天才)优化是{{1}} linq查询。
Batchify
这里,Batchify的目的是确保我们没有帮助 服务器过多,每次操作之间花费相当多的时间 - 数据是以1000个批次发明的,每批都是制造出来的 非常快。
现在,我理解它正在做什么,但我无法分辨出差异,因为我可能会错过它实际工作的方式。 (有时候你认为你知道的事情......直到... )
好的,回到基础:
AFAIK,Linq就像这个链一样 - :
因此,我们无法开始枚举直到 /*1*/ static IEnumerable<T> Batchify<T>(this IEnumerable<T> source, int count)
/*2*/ {
/*3*/ var list = new List<T>(count);
/*4*/ foreach(var item in source)
/*5*/ {
/*6*/ list.Add(item);
/*7*/ if(list.Count == count)
/*8*/ {
/*9*/ foreach (var x in list) yield return x;
/*10*/ list.Clear();
/*11*/ }
/*12*/ }
/*13*/ foreach (var item in list) yield return item;
/*14*/ }
的结果:
select
完成了。
所以基本上我等待让Where-->OrderBy-->Select
所有正确的数据(在 select
之后,之后where
)和只有 - 我的代码可以触及这些值。 (来自orderby
)
但根据我对Marc的回答的理解,似乎select
允许其他资源做某事的yields
之间存在差距......(?)
如果是这样,那么在#4
的每次迭代之间,在行#9
之后,CPU是否有时间做其他事情?
问题
nb的
我已经知道(例如)select
只是:
public static IEnumerable<TResult> Select<TSource,TResult>
(this IEnumerable<TSource> source, Func<TSource,TResult> selector)
{
foreach (TSource element in source)
yield return selector (elem![enter image description here][3]ent);
}
但如果是这样,我的代码无法触及它,直到计算出所有值(where
,orderby
之后)...
对于那些询问是否存在差异的人:http://i.stack.imgur.com/19Ojw.jpg
1M 项目的2 秒。 5M 项 9 秒。
(忽略第二行时间,(额外的console.write行)。)
这里是5米列表:http://i.stack.imgur.com/DflGR.jpg(第一个是withBatchify,另一个不是)
答案 0 :(得分:3)
重要提示:显示的图片包含OrderBy
:您应该注意此在此处中断 batchify,因为OrderBy
是一个缓冲的运算符。我展示的batchify方法适用于非缓冲假脱机流。
在我使用它的上下文中,原点(在batchify之前)是一个迭代器块,它在每次迭代时执行了很多涉及对象创建和伪随机数生成器的事情。因为有问题的代码是时间敏感的,所以不想要做的是在每次调用商店之间引入可靠的暂停(用于创建每个项目的CPU工作)。这部分是为了模拟原始代码,它在前面创建了所有对象,部分是因为我理解SE.Redis如何处理套接字工作。
让我们考虑一下没有Batchify
的行为:
特别是,这意味着商店请求之间存在可预测的暂停。 SE.Redis在专用的工作线程上处理套接字IO,上面的内容很容易导致高分组碎片,特别是因为我使用的是&#34; fire并且忘了&#34;旗。编写器线程需要定期刷新,当 缓冲区达到临界大小或时,它会在出站消息队列中再没有工作。
现在考虑一下batchify的作用:
在这里,您可以看到商店请求之间的CPU工作量显着减少。这更正确地模仿原始代码,其中最初创建了数百万的列表,然后进行迭代。但另外,这意味着创建出站消息的线程很可能至少与编写器线程一样快,这意味着出站队列不可能变为零,因为任何明显的时间。这允许多更低的数据包碎片,因为现在不是每个请求都有一个数据包,因此每个数据包中有多个消息的可能性很大。由于减少了开销,较少的数据包通常意味着更高的带宽。
答案 1 :(得分:0)
我知道这个解决方案是由一个可能比我更了解的用户发布的,但坦率地说,在你的例子中,它没有任何。你在上一篇文章中真正的杀手是你在这个物化集合上启动foreach循环之前使用了List<>
来实际在内存中创建 10M条目 。现在你使用的IEnumerable<>
并没有在内存中同时创建10M,而是一个接一个(如果是并行的话可能更多)。 Batchify方法很不错......但如果你跳过它,它应该工作相同。最好的情况,这是微观优化。