创建具有长时间延迟的任务是不是可以接受?

Posted

技术标签:

【中文标题】创建具有长时间延迟的任务是不是可以接受?【英文标题】:Is it acceptable practice to create Tasks with long delays?创建具有长时间延迟的任务是否可以接受? 【发布时间】:2016-11-10 05:16:13 【问题描述】:

我正在创建一个调度程序以在一天中的特定时间触发事件,为此我正在使用 Task.Delay 来启动任务(一次一个,即仅“下一个”计划)最多延迟几天。例如,在周五下午最后一个事件触发后,我将设置下一个事件,即星期一的某个时间,因此它可能是长达 3 天(约 260,000,000 毫秒)的 TimeSpan。

这是可接受的做法吗?我担心这对于生产环境来说不够稳定/强大。

这里有一些sn-ps的代码来描述我放在一起的内容:

private void SetNextEvent()

    TimeModel next = GetNextScheduledTime();
    Debug.WriteLine($"Next schedule [next.TimeType]: next.Time.ToString("yyyy-MM-dd HH:mm:ss")");

    TimeSpan delay = next.Time.Subtract(DateTime.Now);
    Task.Run(async () =>
    
        await Task.Delay(delay);
        FireEvent(next);
    );


private void FireEvent(TimeModel time)

    Debug.WriteLine($"Event fired [time.TimeType]: DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")");
    OnSchedulerEvent?.Invoke(this, new SchedulerEventArgs  ScheduleType = time.TimeType );
    if (_running)
        SetNextEvent();

【问题讨论】:

它可以工作吗?我想。第一个想法是如果服务器需要重新启动,你会在没有持久状态的情况下被冲洗掉。有很多调度程序,例如专门为此设计的Quartz。我认为他们将是一个更强有力的选择。 如果服务器重新启动,服务将重新启动,它会调用 SetNextEvent,它将返回相同的下一个预定时间,并从那时开始使用 TimeSpan 启动一个任务......我确实考虑过Quartz,不过对于我这两种方法能达到的效果,就显得有点矫枉过正了。 假设您的GetNextScheduledTime 的行为在FireEvent 成功执行之前保持不变,您可能需要检查是否存在否定TimeSpan delay。由于您可能会遇到服务器重新启动时时钟超过下一个预定时间的问题。更糟糕的是,它成功地达到了 -1 毫秒,Task.Delay 永远不会结束。 一个可能的问题是Delay() does not progress when the machine is sleeping。 【参考方案1】:

这是完全可靠的。 .NET 计时器非常有效。最大的问题是您必须假设您的生产应用程序可以随时退出。最容易理解的原因是杀死进程的错误。其他原因包括重新启动、应用程序池回收、部署......

所以,如果你能在被杀后恢复你的状态,那很好。如果您添加有关特定问题的评论,我会解决它们。

看起来您有办法恢复计时器,因为您显然可以计算下一个到期时间。在这种情况下,这样做是非常安全的。您需要确保您的代码始终在运行,例如在重新启动或崩溃后立即。

请注意,IIS 应用程序需要允许同时运行多次。否则,IIS 非常适合您的方案。

【讨论】:

嗨,谢谢,这正是我想要的。我可以轻松地恢复状态,并且我有代码可以检测错过的时间表并“延迟”重播它们,只要它们没有通过截止时间。错过的时间表实际上是可以的,显然不是永久性的,但一次性不是问题。我主要担心的是等待延迟的线程会退出或变得“陈旧”,或者持续时间(天)会导致错误,或者由于某种原因是不可取的。 好问题,但这不是问题。【参考方案2】:

如果您运行的是 Windows,我会使用 TaskScheduler 来执行您想要执行的操作。

运行taskschd.msc,您可以使用该程序来安排定期任务。

右侧面板中应该有一个“创建任务...”按钮。

【讨论】:

这是一种不同的“任务”。 taskschd.msc 调度命令行和可执行类型的任务。任务并行库用于可调用任务,如函数、方法、子例程等。 精确,加上使用 Windows 调度程序意味着我(或者更确切地说,其他人)将不得不手动手动配置数千个计划,从现在到永远更多 @RBarryYoung 这没什么不同。您需要每天运行一些代码,而任务计划程序可以做到这一点。即使您需要您的应用专门执行某些操作,例如更改其内存状态,您仍然可以在初始应用中使用任务调度程序触发 webApi 端点 我真的不喜欢这个操作的任务计划程序的想法,它不能很好地扩展,并且依赖于手动设置,这会给其他自动化部署管道带来风险。我想我可以使用 Powershell 编写脚本,但我不想这样做,因为团队中的每个人都没有这种技能。 @Detail ***.com/questions/7394806/creating-scheduled-tasks【参考方案3】:

我同意 Windows 任务计划程序可能是最好的方法,因为您可以提前知道运行下一个任务的计划。

如果您不提前知道这一点(即等待下一个任务的时间可能会有所不同),那么我建议您在计时器到期时使用计时器和事件处理程序方法。

每次可以设置定时器的Interval属性为等待的时间。当时间到期时,计时器事件处理程序将运行,它可以执行询问并重置计时器的间隔。这似乎比 Task.Delay 更简洁。

【讨论】:

有什么可以证明它是一个更好的解决方案吗?我确实考虑并开始使用 Timers 实现一个解决方案,但对我来说,异步等待方法似乎更干净,并且是我热衷于在团队中推广的一种模式。在被子下面我有点想知道他们是否都在做相对相同的事情...... Task.Delay 确实在后台启动了一个计时器。就资源消耗和解除阻塞线程而言,处理是相同的。我不确定我是否会用“更好”这个词来描述这两种方法。

以上是关于创建具有长时间延迟的任务是不是可以接受?的主要内容,如果未能解决你的问题,请参考以下文章

具有长时间运行任务的单独线程中的计时器

用于较长任务的后台线程

发送 UDP 数据包的长时间延迟

具有长时间运行任务的 Erlang gen_server

调用 record() 时 AVAudioRecorder 长时间延迟

如何最小化创建的 R 代码的不可接受的长时间运行时间