boost::asio很烂吗?

看到知乎上很多大牛的回答/赞同都觉得asio很烂,我没有读过源码也没有用过,不知道asio烂指的是设计上烂(不好用),还是编码上烂呢?

看到知乎上很多大牛的回答/赞同都觉得asio很烂,我没有读过源码也没有用过,不知道asio烂指的是设计上烂(不好用),还是编码上烂呢?

Asio写的非常好!为什么很多人说它性能不好,原因其实很简单。Asio 给出的标准实例,是单个contex可以多线程run,使用该contex进行分发回调。这个模型在window 上的iocp 实现,简直完美,因为接口都是系统api,各个线程等待完成事件都是不需要锁来等待的。锁只需要保护队列即可。Linux 平台,使用epoll模拟,导致一个contex在多个线程run会有一把大锁直接锁调用。其实多线程run就是不同线程切换run,性能的确不行。但是,linux 平台,你可以改变使用习惯,用一个contex进行accept拿到连接,再建立一个contex池,把连接的处理抛到池中执行。跟默认epoll模型一致,也就可以了。手机打字不太好说详细,简单说几个特性。Asio在处理函数调用的时候,用到了本地线程存储,用于频繁回调分配和释放内存的优化,这说明作者对性能是有要求的。Asio的队列是个非常简单的链表结构,所以塔的锁其实临界区执行内容很小的,也算不错的优化。最后,服务端一般都是linux平台,再加上asio本身跨平台,代码量大,模板实现,很多大佬其实没有去看过asio的代码,所以他们的很多结论未必可靠。绝知此事要躬行。代码还是看看好,学习学习也是不错的。可以对比对比libuv和asio,一个纯c单线程事件库,一个c++多线程事件库。我认为是这么理解的。也没人说libuv性能不好,为啥非要说asio坏话?可能因为它的确代码不友好吧。

我来插一句:asio 写起来确实不容易,但是,如果你让一个有经验的 C++ 程序员封装一个跨平台的异步网络库,同时兼顾功能、性能、资源管理、多线程等,他很可能会跟 asio 走一样的路,而且不一定有 asio 走得好。原因是,选择异步模型是为了性能,为了高并发,为了 C10K 问题(否则干嘛不写同步模型);而这些问题缠绕在一起本来就是难题,写出来的代码也就复杂了,你不能指望把这些交给一个新手分分钟搞定吧?用任何库?看电视简单,造电视难,把电视机拆开里面也很复杂。这个世界上复杂不可避免,只能想办法化繁为简。asio 很优秀。

boost asio 有非常好的一面,比如兼容所有操作系统等等,前面的答案说得已经比较完整了,我来补充几点烂的地方,以便大家有宏观完整的认识:1)一次发送多个string功能在linux下的boost asio 实现有bug,至少2017年ubuntu1604自带的boost asio版本是不能用的,一用就直接崩溃。后来重写了一个linux专用multi send解决。黑客攻击模式下,不够稳定:2)黑客发送单字节后硬拆线攻击会直接崩溃。boost asio的非异步read/write在下列场景下会崩溃:高并发下,建立连接后,如果对方反复建连接,随机等一段然后发送硬拆线,即tcp/ip的RST,而不是正常的close,是可以实现一种攻击手段的。因为boost asio会崩溃,backtrace就停在read_some函数上。后来重写了一个linux专用read_some和write_some解决,就是直接调用linux read和write函数解决。3)硬拆线攻击,不能也用硬拆线回击对方。boost asio在使用硬拆线时,如果对方攻击状态下只用硬拆线,服务器端准备也硬拆线,按照asio的范例要修改设置option,再close,有一定概率会崩溃。解决办法,不用硬拆线,只允许用正常close。4)大量新建连接攻击下会死锁。测试复现方法:用boost asio建一个http server,用2组以上的ab本机测试不带-k参数,即每次连接只收发一次后就拆线,每个http都建一次连接,如果提前准备好一下足够小的标准http响应包放到const std:: string中,以便后续足够快的处理,并且服务器代码启用多线程,每个io_service只用一个线程驱动,io_service的数量等于cpu数量,单io_service connect,多 io_service read write这样的结构,开始测试,实际主要瓶颈就在async_accept 上,高并发ab测试,应该在几分钟内就会出现死锁,死在async_accept上,后面所有新建连接都进不来了。解决办法一个是只用单线程不用多线程,另外就是重写linux版本的io_service async_accept。好了,现在系统稳定了,你已经加固完所有的问题点,但是你已经重写了connect,read, write这三个主要动作, 能在黑客攻击下不崩溃的boost asio网络服务器还是要自己来加固一下。

作为网络库他把不同操作系统的底层差异给抹平了,帮干了不少的脏活累活,光这点就很值得夸耀了。同时作为一个异步库也能满足大多数强制场合的需求,即复杂众多io情况。当然它有一些缺点,比如作为大并发场合应用时可能遇到的性能问题,或者将异步应用推广到更一般性的场景下,显得有点格格不入。这其实不能完全归责于asio本身,毕竟那是操作系统和语言本身留下的屁股,让一个库来擦实在有点勉为其难了。你不妨问问那些批判它的家伙们有什么更好的办法,又到底好在哪里,是否处处都强还是有所取舍?

作为网络库他把不同操作系统的底层差异给抹平了,帮干了不少的脏活累活,光这点就很值得夸耀了。同时作为一个异步库也能满足大多数强制场合的需求,即复杂众多io情况。当然它有一些缺点,比如作为大并发场合应用时可能遇到的性能问题,或者将异步应用推广到更一般性的场景下,显得有点格格不入。这其实不能完全归责于asio本身,毕竟那是操作系统和语言本身留下的屁股,让一个库来擦实在有点勉为其难了。你不妨问问那些批判它的家伙们有什么更好的办法,又到底好在哪里,是否处处都强还是有所取舍?

从性能和功能上来说,没得黑。从开发者角度说,烂到极点。api友好度为0,可读性为0,导致要做自定义和扩展的难度高上天,基于asio写的调用代码可读性也极差,维护难度极高。最近公司的框架要做一个网络服务基础件,技术选型最后选了libuv——别看人家是c,实际是全程oo的写法,按c with class的最朴素的cpp思路可以无压力看懂。人家才几十个文件,静态编译才一百多k,所有异步i/o、事件循环的功能应有尽有,所有api加起来才一个头文件,哪怕官方api doc烂到基本等于没有,范例代码里一堆不管擦屁股的坑爹写法,依然可以快速上手。asio呢?呵呵。

说asio烂的都是把asio当成一个网络库看待的,而实际上asio是一个事件框架,并且 可扩展性很强,比如可扩展模拟actor模型,pipeline模型,支持future, 各种静多态支持,异步串口通信,支持自定义部分调度器功能,有栈/无栈协程支持等一堆东西。网络只是asio附带的功能,asio比单纯的网络库复杂多了。

原文地址:https://www.zhihu.com/question/42159518

猜你喜欢

转载自blog.csdn.net/qq_23350817/article/details/96424191