提升deadline_timer最小例子:我应该替换“睡眠”吗?

时间:2013-05-03 08:40:22

标签: c++ boost

我有一个线程,我需要每隔10毫秒做一些事情。所以我有非常简单的代码,如:

while (work) {
    // do something
    Sleep(10000); // boost sleep can be also used
}

我听说一般不建议使用Sleep,如果我用deadline_timer代替它,整体应用程序性能会更好,特别是我会避免昂贵的“上下文切换”。

我应该将sleep更改为deadline_timer吗?如果有,可以举个例子吗?

2 个答案:

答案 0 :(得分:12)

这一切都取决于10ms的要求。


迭代之间延迟10ms

如果应用程序需要在迭代之间延迟10ms,那么睡眠就可以了。假设work()需要7毫秒才能完成,时间线将产生以下结果:

 Time  | Action
-------+------------
0.000s | begin work
0.007s | finish work, block
0.017s | finish blocking, begin work
0.024s | finish work, block
0.034s | finish blocking, begin work

考虑使用Boost.Thread的this_thread::sleep_for()可读性可能值得考虑:

#include <boost/thread.hpp>

int main()
{
  for (;;)
  {
    work();
    boost::this_thread::sleep_for(boost::chrono::milliseconds(10));
  }
}

迭代之间最大延迟10ms

如果迭代之间的最大延迟是10ms,则执行工作所花费的时间需要从10ms延迟减少。假设work()需要7毫秒才能完成,时间线将产生以下结果:

 Time  | Action
-------+------------
0.000s | begin work
0.007s | finish work, block
0.010s | finish blocking, begin work
0.017s | finish work, block
0.020s | finish blocking, begin work

using a timer synchronously教程可以是一个很好的起点。需要考虑的一点是Boost.Asio提供了一些定时器。如果10ms延迟不应受系统时钟更改的影响,则考虑使用steady_timer。否则,deadline_timer应该没问题。

#include <boost/asio/steady_timer.hpp>

boost::asio::io_service io_service;
boost::asio::steady_timer timer(io_service);

int main()
{
  for (;;)
  {
    timer.expires_from_now(boost::chrono::milliseconds(10));
    work();
    timer.wait();
  }
}

另一个考虑因素是,如果work()需要13毫秒才能完成,那么工作之间将没有延迟,因为已经超过了最大延迟。但是,这导致work()每13毫秒完成一次,而不是每10毫秒完成work()

 Time  | Action
-------+------------
0.000s | begin work
0.013s | finish work, block
0.013s | finish blocking, begin work
0.026s | finish work, block
0.039s | finish blocking, begin work

每10毫秒执行一次工作

如果完成work()所需的时间超过延迟,那么work()将不会每10毫秒完成一次。为此,可能需要使用多个线程。以下是一个时间轴,其中2个线程异步执行每10毫秒调度一次的工作,但需要13毫秒才能完成:

 Time  | Thread A                   | Thread B
-------+----------------------------+---------------------------
0.000s | schedule work, begin work  |
0.010s |                            | schedule work, begin work 
0.013s | finish work, block         |
0.020s | schedule work, begin work  |
0.023s |                            | finish work, block
0.030s |                            | schedule work, begin work
0.033s | finish work, block         |

using a timer asynchronously可能会提供基本的介绍。总体思路是将工作添加到io_service中,并且每隔10毫秒,将选择运行io_service的线程来调用work()。可以根据完成所需的时间work()来增加或减少线程池大小。在工作需要7毫秒的情况下,单个线程可以异步等待计时器。

#include <boost/asio/steady_timer.hpp>

boost::asio::io_service io_service;
boost::asio::steady_timer timer(io_service);

void handle_timer(const boost::system::error_code& error);

void schedule_work()
{
  // Schedule more work.
  timer.expires_from_now(boost::chrono::milliseconds(10));
  timer.async_wait(&handle_timer);
}

void handle_timer(const boost::system::error_code& error)
{
  if (error) return;
  schedule_work();
  work();
}

int main()
{
  // Add work to io_service.
  schedule_work();

  // Create 2 threads that will run io_service.
  boost::thread_group threads;
  for (std::size_t i = 0; i < 2; ++i)
    threads.create_thread(boost::bind(
      &boost::asio::io_service::run, &io_service));

  // Wait for threads to finish.
  threads.join_all();
}

在引入并发以满足截止日期时,请验证work()是否是线程安全的。

答案 1 :(得分:1)

使用Sleep()即可。我假设它是Windows API函数,无论如何都需要几毫秒,所以如果你想要10毫秒,你应该传递10而不是10000。

使用像这样的睡眠的简单程序中最大的问题可能是漂移。如果间隔需要非常精确,那么您将面临一些挑战。你没有说你是否关心如果你的实际逻辑需要几毫秒才能完成会发生什么 - 你可以在10毫秒后开始下一次迭代,或者更少以“追赶”。