2

这个问题可能看起来很简单,但我认为它并不是那么微不足道。或者也许我想多了,但我还是想知道。

假设我们必须从 TCP 套接字读取数据,直到遇到一些特殊字符。数据必须保存在某个地方。我们不知道数据的大小,所以我们不知道我们的缓冲区有多大。在这种情况下有哪些可能的选择?

  1. 随着更多数据到达,使用扩展缓冲区realloc这种方法提出了几个问题。使用 realloc 对性能有何影响?它可能会移动内存,所以如果缓冲区中有很多数据(并且可能有很多数据),我们将花费大量时间移动字节。我们应该将缓冲区大小扩展多少?我们每次都加倍吗?如果是,那么所有浪费的空间呢?如果我们稍后以较小的大小调用 realloc,它会截断未使用的字节吗?

  2. 以恒定大小的块分配新缓冲区并将它们链接在一起。这很像 C++ 标准库中的双端队列容器,允许快速添加新数据。这也有一些问题,比如我们应该做多大的块以及如何处理未使用的空间,但至少它具有良好的性能。

你对此有何看法?这两种方法哪个更好?也许还有其他我没有考虑过的方法?

PS:

就个人而言,我更倾向于第二种解决方案,因为我认为如果我们“回收”块而不是每次需要块时都进行动态分配,它可以做得非常快。我能看到的唯一问题是它会损害局部性,但我认为这对我的目的(处理类似 HTTP 的请求)来说并不是非常重要。

谢谢

4

2 回答 2

0

方法 2 听起来更好,但是可能会对您的解析器产生重大影响......即,一旦找到特殊标记,在解析 HTTP 请求时处理非连续缓冲区可能最终比重新分配大缓冲区更昂贵或更复杂(方法1)。Net-net:如果您的解析器很简单,请使用 2,如果不是,请使用 1。

于 2012-12-07T12:55:24.063 回答
0

我更喜欢第二种变体。您也可以考虑只使用一个原始缓冲区并在从套接字接收另一组数据之前处理接收到的数据,即在遇到特殊字符之前开始处理数据。

在任何情况下,我都不建议使用原始内存和重新分配,而是使用std::vector它自己的重新分配,或者std::array用作固定大小的缓冲区。

您可能还对 Boost.Asio 感兴趣,socket_iostream它在原始缓冲区之上提供了另一个抽象层。

于 2012-12-07T09:16:14.543 回答