提升ASIO async_write_some非常慢

时间:2016-05-21 01:56:08

标签: c++ networking boost boost-asio

我终于找到了服务器的瓶颈,结果是async_writeasync_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: %.4f\r\n", (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

这是一个非常慢的游戏服务器,我需要在房间频道中广播数据包,在1个频道中有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 RAM 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 Studio与Microsoft Visual Studio进行内部开发,并在VMWare中运行GCC 4.8.5工具集。

2 个答案:

答案 0 :(得分:0)

如果没有分析器,试图确定哪个指令是瓶颈可能是对耐心的徒劳考验。创建最小示例可以帮助识别特定环境中的问题来源。例如,在既没有I / O争用也没有io_service争用的受控场景中,我在使用native write()Asio's async_write()时观察到0.015ms~写入。

试图解决的问题是以最小延迟向300个对等体写入相同的消息。一种解决方案可能是并行化问题:考虑使用并行运行的n个作业,而不是单个作业将消息串行写入300个对等,并将消息串行写入300/n个对等体。粗略估计一下:

  • 如果连续执行300次写操作,每次写入时间为.015ms(在受控环境中使用本机write()时观察到的平均值),则最后一次写入将在第一次写入后的4.485ms开始。
  • 如果根据潜在的并发限制(本例中为8)批量编写300个写入,则将有8个并行运行的作业串行执行38次写入。如果每次写入需要0.0576ms(在实际系统中观察),则最后一次写入将在第一次写入后的2.13ms开始。

根据上述估计,通过并行解决问题,即使每个asyc_write个操作所花费的时间超过预期,也需要花费一半的时间来写入300个对等体。请记住,这些都是粗略估计,需要进行分析以确定理想的并发数量,并确定潜在的瓶颈。

答案 1 :(得分:0)

我知道这个答案有点晚了,但是我发布它以防有人发现这个有用。

确实在发布完成处理程序时会调用new。但是,官方文档解释了如何进行优化,以便通过实现自定义内存管理来避免相关的运行时开销。这是一个例子: custom memory management for completion handlers