Open guevara opened 2 weeks ago
关于 c++ asio 性能小记 | Jackarain 的 blog https://ift.tt/fwNKYTQ Jack
c++ asio 是一个具有极高性能的网络编程库,因为它完全遵循了 c++ 的 0 开销设计原则,但如果只是参照 asio 的 examples 来实现一些服务,往往有可能在一些情况下并不能发挥出系统的所有性能,下面是我使用 asio 编写高性能服务一些实践中的经验。
c++ asio
c++
asio
examples
一、尽量使用 io_context 池,并将每个 io_context 运行在单线程中,这样可以完全以单线程编程来处理 io 事件,从而避免锁,但需要注意 io_context 池均匀分配给 io 对象(通常使用 round robin 算法),避免线程发生饥饿的情况。在 io_context 构造时,需要注意设置恰当的 concurrency_hint 参数( 参考文档: https://www.boost.org/doc/libs/1_83_0/doc/html/boost_asio/overview/core/concurrency_hint.html),这有非常助于提高性能。
io_context
io
round robin
concurrency_hint
二、定制用户自己的 allocator 以避免 asio 内部 handler 的 op 对象动态内存分配,具体可参考文档:https://www.boost.org/doc/libs/1_83_0/doc/html/boost_asio/overview/core/allocation.html 具体来说: 有的op不需要额外的内存,因为它们已经有了自己的储存空间。 有的op需要一个固定大小的内存块。 有的op则需要一个大小可以变的内存块。 有的op同时需要多个内存块。 还有的op先后需要不同大小的内存块。 但无论是上面哪种情况,通过定制的 allocator 便可完全自如的处理 asio 内存分配事宜,参考示例:https://www.boost.org/doc/libs/1_83_0/doc/html/boost_asio/example/cpp11/allocation/server.cpp
allocator
handler
op
三、非紧急事件投递可使用 defer 而非 post。
defer
post
四、在编写 tcp server 时 listen 设置恰当的 backlog(默认使用 asio::socket_base::max_listen_connections 即可)。另外重要的是,同时多次投递 async_accept 十分有助于大量客户端频繁连接,单个 async_accept 往往会在响应 handle_accept 之时,此时无法及时响应客户端的 connect 请求。 参考文章:https://www.jackarain.org/2023/06/14/asio-acceptor-performance.html
tcp server
listen
backlog
asio::socket_base::max_listen_connections
async_accept
handle_accept
connect
五、在使用 asio 进行 udp 异步编程时,同时多次调用 async_receive_from 可大大提高吞吐量。
udp
async_receive_from
六、使用 asio::io_context::executor_type 而非 asio::any_io_executor 从而避免多态带来的开销。
asio::io_context::executor_type
asio::any_io_executor
七、使用 io_context.poll() 而非 io_context.run(),可以牺牲 CPU 来提高响应速度。
io_context.poll()
io_context.run()
CPU
八、慎用 strand,如无必要不要盲目使用 strand,它主要是被设计在多线程环境中(通常是单个 io_context 运行在多线程),可以保证在其上的异步操作串行化而非加锁,而它在单线程中则没有必要。
strand
九、传输大量数据时,使用自定义的 transfer_at_least 来提升效率,参考文章:https://www.jackarain.org/2023/06/13/asio-transfer_at_least-performance.html
transfer_at_least
十、尽量将 socket 关闭操作让 client 主动发起,以避免服务器上产生过多的 TIME_WAIT 状态
socket
client
TIME_WAIT
暂时只想到这些,以后想到了再更新,以上可根据需要做取舍。
关于 c++ asio 性能小记 | Jackarain 的 blog
https://ift.tt/fwNKYTQ
Jack
c++ asio
是一个具有极高性能的网络编程库,因为它完全遵循了c++
的 0 开销设计原则,但如果只是参照asio
的examples
来实现一些服务,往往有可能在一些情况下并不能发挥出系统的所有性能,下面是我使用asio
编写高性能服务一些实践中的经验。一、尽量使用
io_context
池,并将每个io_context
运行在单线程中,这样可以完全以单线程编程来处理io
事件,从而避免锁,但需要注意io_context
池均匀分配给io
对象(通常使用round robin
算法),避免线程发生饥饿的情况。在io_context
构造时,需要注意设置恰当的concurrency_hint
参数( 参考文档: https://www.boost.org/doc/libs/1_83_0/doc/html/boost_asio/overview/core/concurrency_hint.html),这有非常助于提高性能。二、定制用户自己的
allocator
以避免asio
内部handler
的op
对象动态内存分配,具体可参考文档:https://www.boost.org/doc/libs/1_83_0/doc/html/boost_asio/overview/core/allocation.html 具体来说: 有的op
不需要额外的内存,因为它们已经有了自己的储存空间。 有的op
需要一个固定大小的内存块。 有的op
则需要一个大小可以变的内存块。 有的op
同时需要多个内存块。 还有的op
先后需要不同大小的内存块。 但无论是上面哪种情况,通过定制的allocator
便可完全自如的处理asio
内存分配事宜,参考示例:https://www.boost.org/doc/libs/1_83_0/doc/html/boost_asio/example/cpp11/allocation/server.cpp三、非紧急事件投递可使用
defer
而非post
。四、在编写
tcp server
时listen
设置恰当的backlog
(默认使用asio::socket_base::max_listen_connections
即可)。另外重要的是,同时多次投递async_accept
十分有助于大量客户端频繁连接,单个async_accept
往往会在响应handle_accept
之时,此时无法及时响应客户端的connect
请求。 参考文章:https://www.jackarain.org/2023/06/14/asio-acceptor-performance.html五、在使用
asio
进行udp
异步编程时,同时多次调用async_receive_from
可大大提高吞吐量。六、使用
asio::io_context::executor_type
而非asio::any_io_executor
从而避免多态带来的开销。七、使用
io_context.poll()
而非io_context.run()
,可以牺牲CPU
来提高响应速度。八、慎用
strand
,如无必要不要盲目使用strand
,它主要是被设计在多线程环境中(通常是单个io_context
运行在多线程),可以保证在其上的异步操作串行化而非加锁,而它在单线程中则没有必要。九、传输大量数据时,使用自定义的
transfer_at_least
来提升效率,参考文章:https://www.jackarain.org/2023/06/13/asio-transfer_at_least-performance.html十、尽量将
socket
关闭操作让client
主动发起,以避免服务器上产生过多的TIME_WAIT
状态暂时只想到这些,以后想到了再更新,以上可根据需要做取舍。
via Jackarain 的 blog https://ift.tt/mINOBFr
November 11, 2024 at 07:05PM