【问题标题】:Enforcing process/thread priority in the face of resource starvation在资源匮乏的情况下强制执行进程/线程优先级
【发布时间】:2014-02-20 19:29:25
【问题描述】:

我的应用程序必须每 30 秒 ping 一次(局域网)服务器才能让它知道我还活着。

这很好用,除了当我无法控制的单独进程使用大量系统资源并在它执行其操作时挂起整个机器。结果,我的计时器滴答声被延迟,直到其他进程完成繁重的工作,此时服务器已经认为我已经死了。

其他进程设置为低优先级,我的进程设置为普通优先级。

我的第一次尝试使用System.Timers.Timer 来启动 ping。

在第二次尝试中,我尝试滚动自己的PriorityTimer,以在专用的高优先级线程上运行,但这似乎也收效甚微。

public sealed class PriorityTimer : IDisposable
{
    private int interval;
    private bool active;

    private Thread timerThread;
    private AutoResetEvent resetEvent;

    public event EventHandler Elapsed;

    public PriorityTimer(int interval)
    {
        this.interval = interval;
        resetEvent = new AutoResetEvent(false);
    }

    public bool Enabled
    {
        get { return active; }
        set
        {
            if (active != value)
            {
                active = value;
                if (value)
                {
                    timerThread = new Thread(Wait);
                    timerThread.IsBackground = true;
                    timerThread.Priority = ThreadPriority.Highest;
                    timerThread.Start();
                }
                else
                {
                    resetEvent.Set();
                }
            }
        }
    }

    private void Wait()
    {
        resetEvent.Reset();
        while (!resetEvent.WaitOne(interval))
        {
            if (Elapsed != null)
            {
                Elapsed(this, EventArgs.Empty);
            }
        }
    }

    public void Dispose()
    {
        Enabled = false;
    }
}

假设我不能强制违规进程正常运行,我能做些什么来确保我的计时器在 30 秒后结束?

【问题讨论】:

  • 其他进程占用 CPU 多长时间?
  • @LasseV.Karlsen 它因正在执行的任务(3D 渲染)而异。介于 2 秒到 10 分钟之间。
  • 无论如何,Windows 不是一个实时操作系统,它无法保证您的计时器/线程/代码将获得优先级的速度。在我看来,你最好的选择是让其他过程发挥得很好。你能降低它的优先级吗?
  • 这听起来很奇怪。你确定你没有做一些事情,比如在等待它完成的情况下生成进程,因此你的计时器永远不会启动吗?另外,您确定您的 System.Timers.Timer 事件处理程序没有抛出异常吗?如果事件处理程序抛出一个异常,Timer 将把它压扁,你的程序的其余部分将永远不会知道它。
  • 分页 IO 不受 CPU 优先级影响。任何涉及 CPU 优先级的想法都无济于事。

标签: c# multithreading performance process timer


【解决方案1】:

当大量内存被分页到磁盘时似乎确实会发生这种情况。

您可以尝试将自己的工作集保留在内存中,或者强制其他(流氓)进程消耗更少。后一种策略更可靠。

创建一个Windows Job Object 并配置其最大内存使用量。将有问题的进程分配到作业中。作业能够限制 CPU 使用率和内存。它们旨在“监禁”进程。

【讨论】:

  • 谢谢,我会试试后者,但您能解释一下前一个选项(“将您自己的工作集保存在内存中”)对于 .NET 应用程序的含义吗?
  • 我什至不确定这是否可能。您可以将页面锁定在内存中,但前提是您控制了分配代码(您不使用 .NET)。 Windows 有一个 API 来设置工作集大小,但我认为这不可靠或根本不工作。我不太记得了。即使您设法防止被调出,您的进程也可能依赖于被调出的其他进程。 IOW 你没有很好的选择来强制你自己的工作集保持分页。
  • 还有一个东西叫做内存优先级(google.com/…)。这是相当新的。你可以试试。不过,最好不要让分页启动。
【解决方案2】:

任何不强制执行实时约束的操作系统通常会因争用的某些正常增量而错过计时器请求。您是否一直在跟踪您的增量?

另外,我想问一下您是否使用了垃圾收集语言。如果是这样,暂停肯定会影响计时器结果。

最后,您用来发送心跳的计时器间隔是多少?作为一般经验法则,您应该每间隔发送两次心跳以考虑时间差异。

【讨论】:

  • 语言是标签中提到的c#。计时器应每 30 秒触发一次。轻微的增量是预期和容忍的。事实上,服务器最多可以容忍 90 秒,问题是有时 5 分钟不触发。
  • 这表明操作系统调度程序遵循了一个损坏的调度算法,其他一些假设是错误的。即使进程内存被交换到磁盘,调度程序应该仍然给它 cpu 时间。如果调度程序由于交换而没有给进程足够的 cpu 时间,解决方法可能是将页面锁定到 ram mlockall 中?如果系统正在大量交换,则无论如何您都应该增加内存。最后,另一个调度程序解决方法可能是为进程 pthread_setaffinity_np 设置不相交的 cpu 亲和性?.
  • 我同意 - 它应该仍然获得 cpu 时间,但由于某种原因它不是。 mlockall 是 linux,不是吗?而且线程亲和性是不可能的,繁重的进程必须可以访问所有内核。
  • POSIX,所以它是 POSIX 系列的大部分(Linux、QNX、BSD、OSX 等)。我几乎可以肯定有等效的系统调用,我只是不知道它们是什么。听起来 Windows 作业对象将更好地控制调度和内存使用。如果系统调用在 c# 中不可用,sysinternals 可能有一些用户空间实用程序来修改进程的调度属性?抱歉,我不太了解 Windows 内部结构。
  • 我明白了,谢谢您抽出宝贵的时间。
猜你喜欢
  • 2021-09-15
  • 1970-01-01
  • 2011-06-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-02
  • 2021-05-09
相关资源
最近更新 更多