什么是解决此调度问题的好方法/模式

时间:2009-03-02 12:33:04

标签: design-patterns

我有一个对象

public class Task
{
    public TimeSpan Length { get; set; }
    public IList<Task> Dependencies { get; set; }

    public DateTime? StartDate { get; set; }
}

与其他实例有依赖关系。例如:

(读作“&lt; - ”为“取决于”)

  • B < - A
  • C < - A
  • D&lt; -B,C

  • Q&lt; - P
  • R&lt; -Q

给定一个Tasks *和EndDate列表,我需要在每个任务上设置StartDate,以便它们全部由EndDate完成。任务可以在可能的情况下并行运行,所以......

A必须在B和C之前完成(可以同时完成),D只能在B和C都完成后才能运行。

R必须在Q之后运行,在P之后,但这些可以在parelell中运行到A B C和D.

*列表将完整,所有依赖项将出现在列表中

感谢您的任何建议 安德鲁

6 个答案:

答案 0 :(得分:1)

答案 1 :(得分:1)

您需要计算关键路径。如果有帮助,请参阅this question

否则,这是一个简单的动态编程问题。

答案 2 :(得分:0)

这听起来更像是同步活动。即在线程中你会使用WaitHandles。

A启动并传递B等待句柄和C等待句柄

一旦A完成B和C启动,由于等待句柄被发信号

D有一个等待句柄,在B和C上等待ANY,所以谁先完成将发出信号D

答案 3 :(得分:0)

对于小图,只需递归计算开始日期 - D的开始日期为min(B.StartDate,C.StartDate) - D.Length

对于大型图形,执行拓扑排序,然后可以迭代执行计算。

答案 4 :(得分:0)

    public class Task
    {
        public long Length;
        public List<Task> Dependencies = new List<Task>();
        public DateTime StartDate;
        public DateTime EndDate;

        public void CompleteBaseSchedule()
        {
            DateTime startDate = DateTime.MinValue;
            foreach (Task task in Dependencies)
            {
             startDate = (startDate < task.EndDate) ? task.EndDate : startDate;
                task.CompleteBaseSchedule();

            }
            this.StartDate = startDate;
            this.Length = this.EndDate.Ticks - this.StartDate.Ticks;
        }

主要的某个地方:

            Task task1 = new Task();
            task1.EndDate = new DateTime(2009, 3, 3);
            Task task2 = new Task();
            task1.EndDate = new DateTime(2009, 3, 5);
            Task task3 = new Task();
            task1.EndDate = new DateTime(2009, 3, 2);
            Task task4 = new Task();
            task1.EndDate = new DateTime(2009, 3, 6);
            task4.Dependencies.AddRange(new Task[]{ task1, task2, task3 });

            task4.CompleteBaseSchedule();
            Console.WriteLine(task4.StartDate);
            Console.ReadLine();

答案 5 :(得分:0)

感谢大家的建议,Topological排序的东西很有用,但我想我已经解决了它更简单的方法......

public class Scheduler
{
    private readonly IEnumerable<Task> tasks;
    private readonly DateTime endDate;

    public Scheduler(IEnumerable<Task> tasks, DateTime endDate)
    {
        this.tasks = tasks;
        this.endDate = endDate;
    }

    public void Schedule()
    {
        var terminators = FindTerminators();
        SetStartDatesRecursively(terminators, endDate);
    }

    public ICollection<Task> FindTerminators()
    {
        IList<Task> terminators = new List<Task>();

        foreach(var task in tasks)
        {
            var dependencies = this.tasks.Where(x => x.Dependencies.Contains(task));
            if (dependencies.Count() == 0)
                terminators.Add(task);
        }

        return terminators;
    }

    public void SetStartDatesRecursively(IEnumerable<Task> tasks, DateTime endDate)
    {
        foreach(var task in tasks)
        {
            var startDate = endDate - task.Length;

            if (task.StartDate.HasValue)
                task.StartDate = startDate < task.StartDate ? startDate : task.StartDate;
            else
                task.StartDate = startDate;

            SetStartDatesRecursively(task.Dependencies, task.StartDate.Value);
        }
    }
}