C# 实现抢占式等待队列的最有效方法?
我一直在绞尽脑汁想弄明白这一点。下面是一个场景。我基本上有一个排序的静态列表,其中包含事件应该发生的各种时间。对于可视化:C# 实现抢占式等待队列的最有效方法?,c#,scheduling,scheduled-tasks,C#,Scheduling,Scheduled Tasks,我一直在绞尽脑汁想弄明白这一点。下面是一个场景。我基本上有一个排序的静态列表,其中包含事件应该发生的各种时间。对于可视化: +-----------------------+ | Time | LastUpdate | |-----------------------| | 1 | 03:10:00 | 0 | 2 | 03:10:00 | 1 | 2 | 03:10:00 | 2 | 3 | 03:10:00 |
+-----------------------+
| 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("--------------------------");
}
}
公共静态IList\u列表;
公共无效剂量测定法()
{
while(true)
{
对于(int i=0;i<\u list.Count;i++)
{
var item=新项();
if(DateTime.MinValue.Equals(_list[i].LastUpdate))
{
item=DoWork(_list[i].Url);
_列表[i].LastUpdate=item.LastUpdate;
Console.WriteLine(item.Title+“@”+item.LastUpdate+“i=“+i”);
}
其他的
{
var timeToSleep=((_list[i].LastUpdate.AddMinutes(_list[i].Time)).Subtract(DateTime.Now));
如果(timeToSleep.total毫秒>0)
{
对于(int j=0;j0)
{
WriteLine(“睡眠时间:”+DateTime.Now.Add(timeToSleep));
系统.线程.线程.睡眠(timeToSleep);
}
item=DoWork(_list[i].Url);
_列表[i].LastUpdate=item.LastUpdate;
Console.WriteLine(item.Title+“@”+item.LastUpdate+“i=“+i”);
}
}
Console.WriteLine(“-----------------------------------”);
}
}
如果没有什么需要做的,它将休眠,直到列表中的下一项准备好更新为止。内部for循环被放置到位,以防止更新频率较高的项必须等到更新频率较低的项之后才能再次更新自身。在理想情况下,它将在调用Sleep之前检查上面的任何项目是否需要更新。如果当前项上方的任何项在当前项休眠之前需要更新,请继续并更新它们。如果没有,则当前项将调用Sleep等待,直到它准备好进行更新。我希望这是有道理的
我是不是完全错了?有更简单的解决办法吗?我愿意接受任何建议。此外,请记住,此列表可能会增加到数千项。提前谢谢。我不完全理解您对问题的描述,但这对我来说似乎太复杂了。那么:
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);
}
}
}
公共静态IList\u列表;
公共无效剂量测定法()
{
while(true)
{
DateTime minDate=DateTime.MaxValue;
对于(int i=0;i<\u list.Count;i++)
{
DateTime nextExecution=\u列表[i].LastUpdate.AddMinutes(\u列表[i].Time);
如果(下一步执行0)
{
Console.WriteLine(“睡眠到:”+minDate);
系统.线程.线程.睡眠(timeToSleep);
}
}
}
如果任务数量变大,您可能希望保留一个按下一次计算的执行时间排序的链表。这样,您就不必每次迭代都遍历整个列表。我不完全理解您的问题描述,但这对我来说似乎不必要地复杂。如何:
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);
}
}
}
公共静态IList\u列表;
公共无效剂量测定法()
{
while(true)
{
DateTime minDate=DateTime.MaxValue;
对于(int i=0;i<\u list.Count;i++)
{
DateTime nextExecution=\u列表[i].LastUpdate.AddMinutes(\u列表[i].Time);
如果(下一步执行0)
{
Console.WriteLine(“睡眠到:”+minDate);
系统.线程.线程.睡眠(timeToSleep);
}
}
}
如果任务数量变大,您可能希望保留一个按下一次计算的执行时间排序的链表。这样,您就不必每次迭代都循环遍历整个列表。是的,我确实似乎对复杂化的事情感到不必要。您的解决方案似乎工作得很好。感谢您的帮助。是的,确实如此看来我把事情复杂化了。你的解决方案似乎很有效。谢谢你的帮助。