boost :: asio :: deadline_timer在一段时间后延迟1ms [英] boost::asio::deadline_timer 1ms lags after some time

查看:138
本文介绍了boost :: asio :: deadline_timer在一段时间后延迟1ms的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用boost :: asio :: deadline_timer实现了一个计时器.我使用expires_from_now(boost :: posix_time :: milliseconds(1))运行计时器

I implemented a timer using boost::asio::deadline_timer. I run a timer using expires_from_now(boost::posix_time::milliseconds(1))

我算了一下,它在10秒内(在Windows下)触发的频率.我希望有1万次.

and I count, how often it triggers during the period of 10 seconds (under Windows). I expect 10 000 times.

结果如下:一台PC计数器非常精确-每10秒10000次.在其他PC上,计数器在7000和8500之间随机变化.问题:一段时间后,计数减少到每10秒600-800次.

Results are following: On one PC counter is very accurate - 10 000 times per 10 seconds. On other PC counter varies between 7000 and 8500 randomly. Problem: after some time, the count reduces to 600-800 times per 10 seconds.

当我仍然使用间隔为1毫秒的计时器时,我无法确定将超时增加到〜10-15毫秒的原因是什么.

I cannot find out what is the reason of increasing of the timeout to ~10-15ms when I still use a timer with 1ms interval.

我检查了电源管理中的处理器电源设置-最低性能为100%.Windows中是否还有其他设置可能会影响不同PC上的结果?为什么在运行程序一段时间后会发生这种情况?

I checked processor power settings in power management - minimum performance is 100% . Is there any other settings in Windows that could influence the result on different PCs? Why this happens after some time of running a program?

推荐答案

如果您不以等待的x毫秒为单位,而是依赖于以最精确的精度满足最后期限,则只需对其进行绝对声明:

Instead of waiting "x" milliseconds, if you depend on the deadlines being met with the best possible precision, just state them absolutely:

在Coliru上直播

#include <boost/asio.hpp>
#include <boost/asio/high_resolution_timer.hpp>
#include <iostream>

namespace ba = boost::asio;
using namespace std::chrono_literals;

int main() {
    ba::io_context io;

    using C = ba::high_resolution_timer::clock_type;
    ba::high_resolution_timer t(io);

    auto next_wakeup = [&t, interval = 10ms] {
        t.expires_at(C::now() + interval);
        t.wait();
    };

    auto until = C::now() + 5s;
    int count = 0;

    do count += 1;
    while (next_wakeup(), C::now() <= until);

    std::cout << "Timer triggered " << count << " times in 5s\n";
}

在我的系统上,它报告497,因此您可以看到循环开销足以错过总共几个截止日期.如果降低频率,这一点将变得更加重要.

On my system it reports 497, so you can see the loop overhead is enough to miss a few deadlines in total. This becomes more significant if you make the frequency lower.

您当然可以使事物成为多线程的,并在线程之间分配计时器事件,这样会减少丢失的事件.或者您可以查看 Boost Thread中的实验性调度程序

You could of course make the thing multi threaded and distribute your timer events across threads so there will be fewer missed ones. Or you could look at things like the experimental scheduler in Boost Thread

如果您更改设计折衷方案以最大程度地减少遗漏的事件,那么代价是(可能)具有较高的频率/间隔噪声:

If you change the design trade-offs to minimize missed events, at the cost of (likely) having noisier frequency/intervals:

请注意如何谨慎地计算每次从起始点返回的下一个事件,以便可以以时钟的 time_point无法代表的精度指定 INTERVAL 代码>:

   auto constexpr INTERVAL = 1.0/3ms;

表示.否则,可能会积累舍入误差.

representation. Doing otherwise risks accumulating rounding errors.

在Coliru上直播

#include <boost/asio.hpp>
#include <boost/asio/high_resolution_timer.hpp>
#include <boost/thread.hpp>
using namespace std::chrono_literals;

namespace /*static*/ {
    auto constexpr INTERVAL = 1ms;
    auto constexpr DURATION = 5s;
    std::atomic_int count {0};

    void on_timer_event() { ++count; }
}

namespace ba = boost::asio;
using Timer = ba::high_resolution_timer;
using C = Timer::clock_type;

template <typename Interval>
static void timer_chain(Timer& t, C::time_point start_point, Interval ival, int n = 0) {
    t.expires_at(start_point + std::chrono::duration_cast<C::duration>(n * ival));

    t.async_wait([=,&t](auto ec) {
            if (!ec) {
                on_timer_event();
                timer_chain(t, start_point, ival, n+1);
            }
        });
}

#include <iostream>
int main() {
    ba::io_context io;
    boost::thread_group tg;

    std::list<Timer> timers;

    auto const slices = 10;
    auto const start_point = C::now();
    auto group_interval = INTERVAL * slices;

    for (auto slice = 0; slice<slices; ++slice)
        timer_chain(timers.emplace_back(io), start_point + slice*INTERVAL, group_interval);

    for (unsigned i = 0; i < std::thread::hardware_concurrency(); ++i)
        tg.create_thread([&io] { io.run_for(DURATION); });

    std::cout << "Running on " << tg.size() << " threads...\n";

    tg.join_all();

    std::cout << "Event triggered " << count << " times in " << (C::now() - start_point)/1ms << "ms\n";
}

此打印

Running on 1 threads...
Event triggered 5002 times in 5001ms

或者,在我的系统上:

Running on 8 threads...
Event triggered 5002 times in 5001ms

这篇关于boost :: asio :: deadline_timer在一段时间后延迟1ms的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆