一个大的字节缓冲区或几个小的缓冲区?

问题描述:

我正在学习C#异步套接字编程,并且我已经了解到在某种池中重用字节缓冲区是一个好主意,然后在从套接字接收数据时根据需要检查一次。一个大的字节缓冲区或几个小的缓冲区?

但是,我已经看到了两种不同的字节数组池的使用方法:一种使用简单的队列系统,并根据需要将其从队列中添加/删除。如果请求了一个,并且队列中没有剩余,则会创建一个新的字节数组。

我见过的另一种方法是在整个程序中使用一个大字节数组。队列的思想仍然适用,但它是一个确定要使用的字节数组的片段(偏移量)的整数队列。如果有人被请求并且队列中没有更多信息,则必须调整数组的大小。

其中哪一个是高度可扩展的服务器的更好解决方案?我的直觉是,使用许多字节数组会更便宜,因为我可以想象根据需要调整数组的大小(即使我们将它分成大块)会非常昂贵,特别是当它变大时。使用多个阵列看起来更直观 - 使用一个我没有想到的巨型阵列有什么优势?

你的直觉是正确的。每当你需要增大数组时,你将重新创建数组并复制现有的字节。由于我们在这里讨论的是字节,数组的大小可能会很快变大。所以,每次你都会要求一段连续的内存,这取决于你的程序如何使用内存,可能或不可行。这也将实际上成为一个虚拟池,可以这么说。根据定义,池具有一组由多个客户管理和共享的项目。

一个阵列解决方案的实现方式也更加复杂。好的是,一个数组的解决方案允许你给出可变大小的块,但这是以实质上重新实现malloc为代价的:处理碎片等,这是你不应该考虑的。

多数组解决方案允许您使用N个缓冲区初始化一个池,并以简单的方式轻松管理它们。绝对是我推荐的方法。

我不会建议调整大小选项。从简单开始,继续前进。一个字节缓冲区的队列在耗尽时添加一个新的字节缓冲区将是一个好的开始。您可能不得不关注线程问题,所以我的建议是使用别人的线程安全队列实现。

接下来,您可以看看更复杂的“指针”到一个大的字节数组块中,除非我的建议是有一个4k/16k的队列(某些功率是页面大小的两倍)你索引进入,当它满了时,你会向队列中添加另一个大块。实际上,由于性能的复杂性和可疑的收益,我不推荐这样做。

开始简单,工作你的方式。缓冲池,使其线程安全,看看你是否需要更多。

对多个缓冲区还有一票投票,但除此之外,由于您正在异步执行任务,因此您需要确保您的队列是线程安全的。默认Queue<T>集合绝对是而不是线程安全。

SO用户和MS员工JaredPar在这里有一个很好的线程队列实现:
http://blogs.msdn.com/jaredpar/archive/2009/02/16/a-more-usable-thread-safe-collection.aspx

+0

良好的调用,必须警告不要做像“if(queue.Count> 0){... dequeue ...}”这样的事情。 – user7116 2009-02-24 14:53:07

如果你使用你需要的在需要的时候应该如何快速成长策略单一的缓冲区。如果你以小增量增长它,你可能需要经常做并经常复制所有数据。如果你以大增量增长它(如下一个大小是前一个大小的1.5倍),那么当你尝试增长缓冲区时出现“内存不足”的风险将面临一种情况。对于可扩展系统来说,这是一个双输的选择。这就是为什么重复使用小缓冲区是可取的。

对于垃圾回收堆,您应该始终使用寿命短的小型,正确大小的缓冲区。 .NET堆分配器很快,,代#0集合非常便宜。

当你保留一个静态缓冲区时,你会在程序生命周期中耗尽系统资源。最糟糕的情况是,当它变得足够大以至于移动到大对象堆中时,它将成为无法移动的永久障碍。