Boost ASIO async_write_some确实很慢
Boost ASIO async_write_some is really slow
我终于发现了服务器的瓶颈,原来是async_write
,async_write_some
也是如此。
这里有以下基准代码:
struct timespec start, end;
clock_gettime(CLOCK_MONOTONIC, &start);
//boost::asio::async_write(mMainData.mSocket, boost::asio::buffer(pSendBuff->pBuffer, pSendBuff->dwUsedSize), mMainData.mStrand.wrap(boost::bind(&CServer::WriteHandler, pServer, this, pSendBuff, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)));
mMainData.mSocket.async_write_some(boost::asio::buffer(pSendBuff->pBuffer, pSendBuff->dwUsedSize), (boost::bind(&CServer::WriteHandler, pServer, this, pSendBuff, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)));
clock_gettime(CLOCK_MONOTONIC, &end);
timespec temp;
if ((end.tv_nsec - start.tv_nsec) < 0)
{
temp.tv_sec = end.tv_sec - start.tv_sec - 1;
temp.tv_nsec = 1000000000 + end.tv_nsec - start.tv_nsec;
}
else
{
temp.tv_sec = end.tv_sec - start.tv_sec;
temp.tv_nsec = end.tv_nsec - start.tv_nsec;
}
pLogger->WriteToFile("./Logs/Benchmark_SendPacketP_AsyncWrite.txt", "dwDiff: %.4frn", (float)temp.tv_nsec / 1000000.0f);
输出:
-[2016.05.21 03:45:19] dwDiff: 0.0552ms
-[2016.05.21 03:45:19] dwDiff: 0.0404ms
-[2016.05.21 03:45:19] dwDiff: 0.0542ms
-[2016.05.21 03:45:20] dwDiff: 0.0576ms
这速度慢得离谱,因为它是一个游戏服务器,我需要在一个频道中有300名玩家的房间频道中广播数据包,想象一下它给我的玩家带来的网络延迟。
当然,这个测试是在只有我自己在服务器上的情况下完成的。
是我的代码错了,还是我在ASIO实现逻辑中遗漏了什么?
CXXFLAGS: -ggdb -ffunction-sections -Ofast -m64 -pthread -fpermissive -w -lboost_system -lboost_thread -Wall -fomit-frame-pointer
LDFLAGS: -Wl,-gc-sections -m64 -pthread -fpermissive -w -lboost_system -lboost_thread -lcurl
硬件是:Intel Xeon E3-1231v3(4核,8线程)64GB内存1GBPS上行链路
我正在生产8名ASIO工人。
所以我用调试器进入async_write,发现了这个:
template <typename ConstBufferSequence, typename Handler>
void async_send(base_implementation_type& impl,
const ConstBufferSequence& buffers,
socket_base::message_flags flags, Handler& handler)
{
bool is_continuation =
boost_asio_handler_cont_helpers::is_continuation(handler);
// Allocate and construct an operation to wrap the handler.
typedef reactive_socket_send_op<ConstBufferSequence, Handler> op;
typename op::ptr p = { boost::asio::detail::addressof(handler),
boost_asio_handler_alloc_helpers::allocate(
sizeof(op), handler), 0 };
p.p = new (p.v) op(impl.socket_, buffers, flags, handler);
BOOST_ASIO_HANDLER_CREATION((p.p, "socket", &impl, "async_send"));
start_op(impl, reactor::write_op, p.p, is_continuation, true,
((impl.state_ & socket_ops::stream_oriented)
&& buffer_sequence_adapter<boost::asio::const_buffer,
ConstBufferSequence>::all_empty(buffers)));
p.v = p.p = 0;
}
为什么要在一个本应是高性能的库中调用boost::asio的"new"?有没有预先创建它试图分配的内容?很抱歉,我无法描述内部结构,因为我使用Visual GDB和Microsoft Visual Studio进行开发,GCC 4.8.5工具集在VMWare中运行。
我知道这个答案有点晚了,但我会发布它,以防有人觉得它有用。
事实上,当发布完成处理程序时,会调用new。然而,官方文档解释了如何通过实现自定义内存管理来进行优化,从而避免相关的运行时开销。以下是示例:完成处理程序的自定义内存管理
如果没有探查器,试图确定哪条指令是瓶颈可能是徒劳的耐心测试。创建一个最小的示例可能有助于识别特定环境中问题的根源。例如,在既没有I/O也没有io_service
争用的受控场景中,当使用本机write()
和Asio的async_write()
时,我观察到0.015ms~的写入。
试图解决的问题是以最小的延迟向300个对等体写入相同的消息。一种解决方案可能是将问题并行化:与其让单个作业将消息串行写入300个对等体,不如考虑使用并行运行的n
作业,并将消息串行写到300/n
个对等体。粗略估计:
- 如果连续执行300次写入,每次写入花费.015ms(在受控环境中使用本机
write()
时观察到的平均值),则最终写入将在第一次写入后4.485ms开始 - 如果根据潜在的并发限制(本例中为8)分批进行300次写入,则将有8个作业并行运行,串行执行38次写入。如果每次写入花费0.0576ms(在实际系统上观察到),则最终写入将在第一次写入后2.13ms开始
根据上述估计,通过并行该问题,即使每个单独的asyc_write
操作的时间比预期的要长,写入300个对等点也需要一半的时间。请记住,这些都是粗略的估计,需要进行分析以确定理想的并发量,并确定潜在的瓶颈。
- 理解boost::asio-async_read在无需读取内容时的行为
- 提升 ASIO 无法识别计时器对象
- C++Boost Asio Pool线程,带有lambda函数和传递引用变量
- boost::asio::steady_timer()与sleep()我应该使用哪一个
- boost::asio如何生成多个协同程序,然后加入它们
- 尝试链接我的着色器时,我收到错误代码"error c5145 must write to gl_position"
- 缓慢提升ASIO
- 从 Boost ASIO 获取 epoll 描述符 io_service对象
- 如何在 Boost.Asio 中使用 Zero-copy sendmsg/receive
- asio::read() 需要很长时间,使用 asio::write 没有问题
- 在 boost::asio::write 之后使用 TCP
- boost::asio::write() VS socket->write_some()
- 使用无效套接字调用boost::asio::write()使我的Blackberry 10应用程序崩溃
- boost::asio::write UNICODE
- write_some vs write - boost asio
- Boost TCP服务器在执行asio::write操作时客户端断开,导致服务器崩溃
- boost::asio::read防止boost:asio::write向Java Socket发送数据
- 如何使用 boost::asio:write 调用发送 ICU UnicodeString
- 使用boost::asio::write()永远不会设置boost::system::error_code
- Error when boost::asio::write