【问题标题】:Most efficient way to implement preemptive waiting queue?实现抢占式等待队列的最有效方法?
【发布时间】:2010-11-13 21:36:02
【问题描述】:

我一直在绞尽脑汁想弄清楚这一点。这是场景。我基本上有一个排序的静态列表,其中包含一个事件应该发生的不同时间。对于可视化:

+-----------------------+
|  Time  |  LastUpdate  |
|-----------------------|
|    1   |   03:10:00   | 0
|    2   |   03:10:00   | 1
|    2   |   03:10:00   | 2
|    3   |   03:10:00   | 3
|    3   |   03:10:00   | 4
|    4   |   03:10:00   | 5
+-----------------------+

所以,第一次通过该方法时,lastTime 属性将为空,因此它将“做一些工作”并将 lastTime 属性设置为当前时间。 time 属性表示何时需要再次执行该项目。例如,由于元素 0 具有 03:10:00lastTime 和 1 的时间,它需要在 03:11:00 处执行,元素 1 和 2 都具有 lastTime03:10:00 并且都需要在03:12:00 处执行,以此类推。

下面是我的粗略实现:

public static IList<Item> _list;

public void DoSomething()
{
    while (true)
    {
        for (int i = 0; i < _list.Count; i++)
        {
            var item = new Item();

            if (DateTime.MinValue.Equals(_list[i].LastUpdate))
            {
                item = DoWork(_list[i].Url);
                _list[i].LastUpdate = item.LastUpdate;
                Console.WriteLine(item.Title + " @ " + item.LastUpdate + "; i = " + i);
            }
            else
            {
                var timeToSleep = ((_list[i].LastUpdate.AddMinutes(_list[i].Time)).Subtract(DateTime.Now));

                if (timeToSleep.TotalMilliseconds > 0)
                {
                    for (int j = 0; j < i; j++)
                    {
                        var lastRet = _list[j].LastUpdate.AddMinutes(_list[j].Time);
                        var nextFetch = DateTime.Now.Add(timeToSleep);

                        if (lastRet < nextFetch)
                        {
                            item = DoWork(_list[i].Url);
                            _list[i].LastUpdate = item.LastUpdate;
                            Console.WriteLine(item.Title + " @ " + item.LastUpdate + "; i = " + i);
                        }
                    }
                }

                if (timeToSleep.TotalMilliseconds > 0)
                {
                    Console.WriteLine("Sleeping until: " + DateTime.Now.Add(timeToSleep));
                    System.Threading.Thread.Sleep(timeToSleep);
                }

                item = DoWork(_list[i].Url);
                _list[i].LastUpdate = item.LastUpdate;
                Console.WriteLine(item.Title + " @ " + item.LastUpdate + "; i = " + i);
            }
        }

        Console.WriteLine("--------------------------");
    }
}

如果没有什么需要做的,它会休眠直到列表中的下一个项目准备好更新。内部 for 循环被放置在适当的位置,以防止更频繁更新的项目必须等到更新频率较低的项目才能再次更新自身。在理想情况下,它会在调用 Sleep 之前检查它上面的任何项目是否需要更新。如果当前项目之上的任何项目需要在当前项目休眠之前更新,则继续更新它们。如果没有,则当前项目将调用 Sleep 以等待它准备好更新。我希望这是有道理的。

我这样做完全错了吗?有没有更简单的解决方案?我对任何和所有建议持开放态度。另外,请记住,此列表可能会增长到数千个项目。提前致谢。

【问题讨论】:

    标签: c# scheduling scheduled-tasks


    【解决方案1】:

    我不完全理解您的问题描述,但这对我来说似乎不必要地复杂。怎么样:

    public static IList<Item> _list;
    
    public void DoSomething()
    {
        while (true)
        {
            DateTime minDate = DateTime.MaxValue;
    
            for (int i = 0; i < _list.Count; i++)
            {
                DateTime nextExecution = _list[i].LastUpdate.AddMinutes(_list[i].Time);
    
                if (nextExecution <= DateTime.Now)
                {
                    var item = DoWork(_list[i].Url);
                    _list[i].LastUpdate = item.LastUpdate;
                    nextExecution = _list[i].LastUpdate.AddMinutes(_list[i].Time);
                    Console.WriteLine(item.Title + " @ " + item.LastUpdate + "; i = " + i);
                }
    
                if (nextExecution < minDate)
                    minDate = nextExecution;
            }
    
            TimeSpan timeToSleep = minDate.Subtract(DateTime.Now));
    
            if (timeToSleep.TotalMilliseconds > 0)
            {
                Console.WriteLine("Sleeping until: " + minDate);
                System.Threading.Thread.Sleep(timeToSleep);
            }
        }
    }
    

    如果任务数量变大,您可能希望保留一个按下一次计算的执行时间排序的链表。这样,您不必每次迭代都遍历整个列表。

    【讨论】:

    • 是的,看起来我确实不必要地过度复杂化了事情。您的解决方案似乎工作正常。感谢您的帮助。
    猜你喜欢
    • 2012-10-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-09
    • 2011-03-20
    • 2018-09-16
    • 1970-01-01
    • 2014-11-18
    相关资源
    最近更新 更多