2

我发现asio的buffer的引用语义使用起来不方便。它需要用户在堆中分配数据,但是对于小数据(例如,100 Byte),在堆栈上分配并复制几次(我认为使用 asio 时复制次数应该小于 3)会比调用一个新的操作。例如:

class MyData {
    std::vector<char> data;
};

void hander(Request req) {
    MyData d;
    async_write(buffer(d.data)...);
} // oops, d was destroyed, but the actual write have not execute

// this is ok, but awkward and poor performance if data is very small
void hander(Request req) {
    shared_ptr<MyData> d(new MyData());
    async_write(buffer(d->data)...bind(&X::handle_write, this, d);
}
void handle_write(shared_ptr<MyData> s) {
}

为什么 asio 没有提供可以进行深拷贝的缓冲区?它将节省性能的复制时间,但对于应用程序发送大量小数据,性能应该更差

在其文档中,连接对象有一个用于保存数据的成员,但对于大多数应用程序来说,一个数据成员是不够的。当应用程序可以随时写入数据时需要使用队列(不喜欢 HTTP 等半双工协议),否则数据可能会被下一次写入覆盖。所以如果队列是Queue,那还需要调用new,如果队列是Queue,那还需要copy

4

2 回答 2

3

Boost.Asio 的缓冲区类型对实际内存需要分配的位置没有任何要求。它只要求它将代表的内存是连续的,当它不连续时,就需要使用缓冲区序列。

Boost.Asio 提供了buffer_copy可用于执行从一个缓冲区或缓冲区序列到另一个缓冲区的深度复制。纯属推测,但 Asio 可能不会提供拥有底层内存的缓冲区,因为:

  • 内存使用特性因应用程序而异。是否有一个好的默认分配或所有权策略可供使用并不明显。
  • boost::buffer()提供了一种从各种类型(原始内存、c-array、、、和)创建 Boost.Asio 缓冲区的boost/std::array便捷std::vector方法std::string。其中一些类型已经提供了自定义分配的方法,以及执行深度复制的方法(复制构造函数、赋值等std::copy)。
  • Boost.Asio 操作是针对缓冲区序列的概念/类型要求实现的,例如 MutableBufferSequence,而不是实际类型,例如boost::asio::mutable_buffers. 因此,只要满足类型要求,用户就可以自由使用自己的类型和内存管理。这是引用计数缓冲区的官方示例。

在分析并确定分配和副本是瓶颈之后,然后考虑采用旨在解决特定问题的技术:

  • 内存池将允许重用内存,而不是将内存释放回空闲存储区。
  • 在某些情况下,引用计数缓冲区可以消除执行深度复制的需要。考虑使用官方示例或boost/std::shared_ptr. 这些甚至可以通过使用自定义删除器由池管理的类型使用。
  • 对于唯一所有权,std::unique_ptr和/或移动语义也可以删除不必要的深层副本。
于 2013-06-27T15:49:07.937 回答
0

ASIO 没有提供这样的缓冲类,但是自己写一个是可行的。Buffers示例也有此类的实现。

为了提高性能,可以组织一个池,例如,WebSocket++库使用自己的消息池

于 2013-06-27T15:20:50.100 回答