我是boost :: asio的初学者。
我需要编写一个从管道读取并将数据放入环形缓冲区的模块(我对如何实现这部分没有任何问题)。
模块的另一部分等待消费者打开新的TCP连接或unix域套接字,当建立连接时,它会发送完整的环形缓冲区内容,然后它会在推送到任何新数据后立即发送环形缓冲区。允许多个消费者,一个消费者可以随时打开新的连接。
我想到的第一个天真实现是为每个连接保留一个单独的asio :: streambuf,并在连接时将整个环形缓冲区推入其中,然后是每个新数据,但这似乎是一个非常次优的方法。因为我不知道boost :: asio :: send(或linux tcp / ip stack)是否复制数据,所以在内存和cpu周期都需要为每个连接复制数据,可能需要多次
由于我的想法是根本不使用多线程,我考虑使用某种形式的自定义asio :: streambuf派生类,它与环形缓冲区共享实际缓冲区,但保持单独的状态无需任何锁即可读取指针。
看来我的这是一个非常不寻常的需求,因为我无法找到任何涉及类似主题的相关文档/问题,并且提升文档对我来说似乎非常简短和稀缺(参见eg:{{ 3}})。
如果有人可以指出一些我可以作为实现我的设计的起点的想法,或者如果他/她认为我的不好,不可执行和/或可以改进的话,那么我会很高兴。 / p>
答案 0 :(得分:1)
你应该做你想做的事。
你绝对不需要streambuf
与Boost Asio一起使用:http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/buffer.html
如果问题是如何避免生产者“等待”直到所有消费者(读取:连接)都完成传输数据,你总是可以使用交替输出缓冲区的 ye olde trick 。 / p>
许多环形缓冲区实现允许一次直接拼接完整的元素序列(例如boost lockfree spsc_queue cache memory access)。你可以使用这样的操作。
也相关:
答案 1 :(得分:0)
看来,表演是一个主题。 无论是使用boost :: asio还是一些手工编织的解决方案,性能(吞吐量)可能已经由事实(如OP的注释部分所述)消耗掉,单个字节正在被交易(从管道) 在消费者连接的初始“突发阶段”之后,单个字节从管道流向连接的消费者套接字,每个字节使用read()和write()操作(如果应用程序不经常轮询,则为几个字节)。登记/> 鉴于(系统调用read()和write()的价格是为少量数据支付的事实),我敢于理解任何关于多个队列或单个队列等的事情已经处于基本“设计的阴影中”缺陷”。我把“设计缺陷”放在引号中,因为不能总是避免必须处理这种情况。
因此,如果无论如何都无法优化吞吐量,我会推荐可以构思的最简单直接的解决方案。
OP中的“无线程”语句意味着接受套接字,消费者数据套接字和管道的非阻塞文件描述符。这是另一个100%CPU /核心吃轮询应用程序吗?如果这不是某种特殊的ops超优化问题,我宁愿不建议使用非阻塞文件描述符。另外,我不担心零拷贝。
使用线程的一种简单方法是使消费者套接字无阻塞,而管道处于阻塞模式。然后,读取管道的线程将数据泵入队列并调用为所有当前连接的消费者提供服务的功能。当新客户端连接处于挂起状态时,侦听套接字(一个调用accept())处于信号状态。使用kqueue(bsd)或epoll(linux等)或WaitForMultipleObjects(windows)等机制,管道读取器线程也可以对这种情况作出反应。
在没有任何事情要做的时候,你的应用程序正在睡觉/阻塞并且对我们的环境友好:)