Самый эффективный способ реализовать упреждающую очередь ожидания?

Я ломал голову, пытаясь понять это. Вот сценарий. По сути, у меня есть отсортированный статический список, который содержит разное время, когда должно произойти событие. Для визуализации:

+-----------------------+
|  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 будет иметь значение null, поэтому оно «выполнит некоторую работу» и установит для свойства lastTime текущее время. Свойство time указывает, когда элемент нужно будет выполнить снова. Например, поскольку элемент 0 имеет lastTime из 03:10:00 и время 1, его нужно будет выполнить в 03:11:00, элементы 1 и 2 имеют lastTime из 03: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, чтобы дождаться, когда он будет готов к обновлению. Я надеюсь в этом есть смысл.

Я делаю это совершенно неправильно? Есть ли более простое решение для этого? Я открыт для любых предложений. Кроме того, имейте в виду, что этот список потенциально может вырасти до тысяч элементов. Заранее спасибо.


person user135383    schedule 24.07.2009    source источник


Ответы (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);
        }
    }
}

Если количество задач становится большим, вы можете сохранить связанный список, упорядоченный по следующему расчетному времени выполнения. Таким образом, вам не нужно перебирать весь список на каждой итерации.

person Thorarin    schedule 24.07.2009
comment
Да, похоже, я излишне усложнял вещи. Ваше решение работает нормально. Спасибо за помощь. - person user135383; 27.07.2009