2012-03-20 184 views
7

我正在写一个异步日志记录框架,我有多个线程转储数据。我开始玩Boost asio,因为它提供了一些简单的方法来执行序列化和订购。因为我是初学者,所以我开始使用线程安全(使用boost::mutexboost:condition_variable)circular bounded_buffer(实际上是vector)的设计。Boost ASIO IO_SERVICE实现?

我写了一个简单的基准来测量性能。基准测试只是一个记录一百万条消息的单线程(将它推入缓冲区),而我的工作线程只会从队列中获取消息以登录到文件/控制台/记录器列表。 (P.S.使用互斥体和C.V是正确的,消息的指针正在移动,所以从这个角度来看,一切都很好/有效)。

当我改变了我的执行,而不是使用boost::asio::io_service和和具有单个线程执行run()性能确实提高了(其实它真的缩放以及对增加在我最初的简单模型,而不是降低性能正在记录的信息的数量)

这里有几个问题,我想清除。

  1. 为什么要提高性能? (我认为boost::asio::io_service内部实现具有处理程序的线程安全队列,这使得它比我自己的初始简单线程安全队列设计更有效率)。请注意,我的设计经过了充分的审查,没有出现任何错误(骨架代码基于已证明的示例),是否有人可以更详细地了解io_service如何实现此目的的内部细节。第二个有趣的观察是,在增加线程时,我的初始实现性能得到了改善,但是以丢失序列化/排序为代价,但性能随boost :: asio降低(非常轻微)(我认为这是因为我的处理程序做了非常简单的任务,并且上下文切换开销正在下降,我会尝试执行更复杂的任务并在稍后发布我的观察结果)。

  2. 我真的很想知道boost::asio只是用于I/O和网络操作,还是我用它来通过线程池执行并行任务(并行)是一种很好的设计方法。 io_service对象只是用于I/O对象(如文档中所写),但我发现它是一种非常有趣的方式,可以帮助我以序列化的方式解决并发任务(不仅仅是I/O或与网络相关的任务)使用股线进行排序)。我很兴奋,并且很好奇为什么基本模型没有执行/缩放以及当我使用boost asio。

结果:(在我刚1个工作线程)

  • 1000任务:在这两种情况下
  • 10微秒/任务
  • 10000任务:80微秒(有界缓冲液),在升压10微秒ASIO
  • 100000任务:250微秒(bounde缓冲液),在升压10微秒ASIO

这将是有趣到k现在如何提升解决线程安全问题io_service处理程序的线程安全队列(我总是认为在某种程度上的实现,他们也必须使用锁和c.v)。

+0

我已经使用'boost :: asio'来管理其他类型的异步任务(不仅仅是网络IO)以取得良好的成功。 – Chad 2012-03-20 15:13:00

+0

我知道这是一个老问题,但可能(在Windows上),ASIO使用IO完成端口,这可能会导致总体系统调用较少。 – Pete 2013-10-22 08:21:09

回答

4

我怕我忍不住多用(1),但相对于其他两个问题:

(2)我发现有在boost::asio架构的一些费用是不 - 确定性的,即进入(或发送到IO服务对象)的数据之间的延迟可以从几乎即时响应变化到几百毫秒的量级。我试图量化这个问题,作为我试图解决的关于记录和时间戳RS232数据的另一个问题的一部分,但没有得到任何确定的结果或稳定延迟的方法。我不会感到惊讶的发现类似的问题存在于上下文切换组件中。 (3)就异步I/O以外的任务而言,使用boost::asio,它现在是我大部分异步操作的标准工具。我一直使用boost::asio定时器进行异步处理,并为其他任务生成超时。将多个工作线程添加到池中的能力意味着您可以很好地扩展其他异步高负载任务的解决方案。我简单和最喜欢的课我已经写在过去的一年是boost::asio IO服务一个小小的工作线程类(道歉,如果有任何错别字,这是从内存中转录,而不是切&粘贴):

class AsioWorker 
{ 
public: 
    AsioWorker(boost::asio::io_service * service): 
    m_ioService(service), m_terminate(false), m_serviceThread(NULL) 
    { 
    m_serviceThread = new boost::thread(boost::bind(&AsioWorker::Run, this)) 
    } 
    void Run(void) 
    { 
    while(!m_terminate) 
     m_ioService->poll_one(); 
     mySleep(5); // My own macro for cross-platform millisecond sleep 
    } 
    ~AsioWorker(void) 
    { 
    m_terminate = true; 
    m_serviceThread->join(); 
    } 
private: 
    bool m_terminate; 
    boost::asio::io_service *m_ioService; 
    boost::thread *m_serviceThread; 
} 

这个班级是一个很棒的小玩具,只需要加上new就可以了,有些则在delete之后。将一个std::vector<AsioWorker*> m_workerPool粘贴到使用boost::asio的设备类中,您甚至可以进一步包装线程池管理内容。我一直很想写一个智能池自动管理器,根据时间适当增加线程池,但是我还没有一个项目需要它。

关于满足您对线程安全的好奇心,可以深入了解提升的内容,以准确找出他们如何完成自己的工作。就我个人而言,我总是将大部分提升的东西用于面值,并从过去的经验中认为它在引擎盖下非常优化。

0

我也发现boost::asio是一般多核处理引擎的优秀基础设施。我在很多同步的细粒度任务上测量了它的性能,发现它的性能超过了我使用C++ 11线程和条件变量编写的“经典”实现。

它也跑赢TBB,但不是那么多。我深入研究他们的代码,试图找到“秘密”。我唯一能想到的就是他们的队列是一个经典的链表,而不是一个stl容器。

对于这一切,我不知道如何asio将缩减在大量线程架构像至强融核。这两个东西,似乎缺少有:

  1. 优先级队列和
  2. 一个工作窃取队列。

我怀疑添加这些功能会降低到TBB性能水平。