如何在一个时间线上有效地处理传入的延迟事件



我想实现等待一些事件并在一些延迟后处理它们的算法。每个事件都有自己预定义的延迟。处理程序可以在单独的线程中执行。CPU节流、主机过载等问题可能会被忽略——它不是一个精确的实时系统。

示例

  • 在N到达的时刻,一个延迟1秒的事件。我们想在N+1秒的时刻处理它
  • 在N+0.5秒到达另一个事件,延迟0.3秒。我们想在N+0.8秒的时刻处理它

方法

我想到的唯一简单的方法是在迭代之间使用一个延迟尽可能小的循环,比如每10毫秒一次,并检查是否现在应该处理我们时间线上的任何事件。但这不是一个好主意,因为延迟可能从10毫秒到10分钟不等。

另一种方法是让一个线程在事件之间休眠。但我不知道如何有力地"唤醒";它是在从现在到下一次预定唤醒之间应该处理的新事件时发生的。

此外,每个事件使用一个线程并只休眠也是可能的,但可能会有数千个同时发生的事件,这可能会导致线程耗尽。

该解决方案可能与语言无关,但我更喜欢C++STD库解决方案。

另一种方法是使用一个在事件之间休眠的线程。但我不知道如何有力地"唤醒";它是在从现在到下一次预定唤醒之间应该处理的新事件时发生的。

我想这些问题的解决方案是,至少在*nix系统上,在计时器的帮助下进行轮询或epoll。它允许您使线程休眠,直到某个给定的事件。给定的事件可能是出现在stdin上的事件或计时器超时。由于问题是关于一般算法/算法思想的,并且代码会占用大量空间,我只给出伪代码

epoll = create_epoll();
timers = vector<timer>{};
while(true) {
event = epoll.wait_for_event(timers);
if (event.is_timer_timeout()) {
t = timers.find_timed_out();
t.handle_event();
timers.erase(t);
} else if (event.is_incoming_stdin_data()) {
data = stdin.read();
timers.push_back(create_timer(data));
}
}

共享优先级队列的两个线程。

到达线程:等待到达。当事件到达时,计算处理程序运行的时间。将处理程序添加到具有处理程序时间优先级的队列中(队列顶部将是要处理的下一个事件

处理程序线程:现在等于处理程序在队列顶部的时间,然后运行处理程序。睡眠以获得时钟分辨率。

注意:请检查您的队列是否是线程安全的。如果没有,那么您将不得不使用互斥锁。

这看起来很简单,但有很多棘手的事情等着没有经验的人。所以,我不建议从头开始编码。最好使用图书馆。经典的是boost::asio。然而,这开始显示出它的年龄,并且有比需要的更多的铃声和口哨声。因此,就我个人而言,我使用了一些更轻量级的东西,并在C++17中进行了编码——我编码的一个非阻塞事件服务类,您可以从中获得https://github.com/JamesBremner/await.注意使用这个类的示例应用程序,它完成了您所需要的大部分工作https://github.com/JamesBremner/await/wiki/Event-Server

最新更新