Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/284.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何使用LINQ to对象在不重叠的情况下调度作业?_C#_.net_Linq_Indexing_Clr - Fatal编程技术网

C# 如何使用LINQ to对象在不重叠的情况下调度作业?

C# 如何使用LINQ to对象在不重叠的情况下调度作业?,c#,.net,linq,indexing,clr,C#,.net,Linq,Indexing,Clr,这是另一个资源分配问题。我的目标是运行一个查询,将任何时间段的最高优先级作业分配给两个CPU内核中的一个(只是一个示例,所以假设没有中断或多任务)。注意:这与类似,但重点是重叠时间和分配多个项目,而不仅仅是最高优先级的项目 我们的目标是: public class Job { public int Id; public int Priority; public DateTime Begin; public DateTime End; } 真实的数据集非常大,但在

这是另一个资源分配问题。我的目标是运行一个查询,将任何时间段的最高优先级作业分配给两个CPU内核中的一个(只是一个示例,所以假设没有中断或多任务)。注意:这与类似,但重点是重叠时间和分配多个项目,而不仅仅是最高优先级的项目

我们的目标是:

public class Job
{
    public int Id;
    public int Priority;
    public DateTime Begin;
    public DateTime End;
}
真实的数据集非常大,但在本例中,假设有1000个作业要分配给两个CPU核心。它们都加载到内存中,我需要对它们运行一个LINQ to对象查询。目前这需要将近8秒和140万次比较

我利用了文中引用的逻辑来确定两个项目是否重叠,但与那篇文章不同的是,我不需要简单地查找重叠的项目,而是安排任何重叠集的顶部项目,然后安排下一个项目

在我开始编写代码之前,让我指出当前不完善算法的步骤:

  • 确定剩余作业(通过删除任何已分配的作业)
  • 通过自连接所有剩余作业并按优先级选择顶部重叠作业,将作业分配给当前核心。
  • 通过执行查询来连接新作业
  • 对每个剩余堆芯重复从停止点1开始的操作 问题:

    • 如何才能最有效地做到这一点?
    • 我可以避免步骤2中的子查询吗?可能是通过分组,但我不确定如何基于.Overlaps()扩展方法进行分组。
    • 作业已被订购。步骤2是否可以利用这一事实,即只在短范围内比较项目,而不是每个作业?
    • 是否有比循环更有效的方法分配给核心?这可以避免执行步骤3中的查询吗?同样,如果我可以对重叠作业集进行分组,那么分配核心只需为每个重叠集选择N个即可。
    完整示例代码:

    public class Job
    {
        public static long Iterations;
    
        public int Id;
        public int Priority;
        public DateTime Begin;
        public DateTime End;
    
        public bool Overlaps(Job other)
        {
            Iterations++;
            return this.End > other.Begin && this.Begin < other.End;
        }
    }
    
    public class Assignment
    {
        public Job Job;
        public int Core;
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            const int Jobs = 1000;
            const int Cores = 2;
            const int ConcurrentJobs = Cores + 1;
            const int Priorities = Cores + 3;
            DateTime startTime = new DateTime(2011, 3, 1, 0, 0, 0, 0);
            Console.WriteLine(string.Format("{0} Jobs x {1} Cores", Jobs, Cores));
            var timer = Stopwatch.StartNew();
    
            Console.WriteLine("Populating data");
            var jobs = new List<Job>();
            for (int jobId = 0; jobId < Jobs; jobId++)
            {
                var jobStart = startTime.AddHours(jobId / ConcurrentJobs).AddMinutes(jobId % ConcurrentJobs);
                jobs.Add(new Job() { Id = jobId, Priority = jobId % Priorities, Begin = jobStart, End = jobStart.AddHours(0.5) });
            }
            Console.WriteLine(string.Format("Completed in {0:n}ms", timer.ElapsedMilliseconds));
            timer.Restart();
    
            Console.WriteLine("Assigning Jobs to Cores");
            IEnumerable<Assignment> assignments = null;
            for (int core = 0; core < Cores; core++)
            {
                // avoid modified closures by creating local variables
                int localCore = core;
                var localAssignments = assignments;
    
                // Step 1: Determine the remaining jobs
                var remainingJobs = localAssignments == null ? 
                                                    jobs :
                                                    from j in jobs where !(from a in localAssignments select a.Job).Contains(j) select j;
    
                // Step 2: Assign the top priority job in any time-slot to the core
                var assignmentsForCore = from s1 in remainingJobs
                                  where
                                      (from s2 in remainingJobs
                                       where s1.Overlaps(s2)
                                       orderby s2.Priority
                                       select s2).First().Equals(s1)
                                  select new Assignment { Job = s1, Core = localCore };
    
                // Step 3: Accumulate the results (unfortunately requires a .ToList() to avoid massive over-joins)
                assignments = assignments == null ? assignmentsForCore.ToList() : assignments.Concat(assignmentsForCore.ToList());
            }
    
            // This is where I'd like to Execute the query one single time across all cores, but have to do intermediate steps to avoid massive-over-joins
            assignments = assignments.ToList();
    
            Console.WriteLine(string.Format("Completed in {0:n}ms", timer.ElapsedMilliseconds));
            Console.WriteLine("\nJobs:");
            foreach (var job in jobs.Take(20))
            {
                Console.WriteLine(string.Format("{0}-{1} Id {2} P{3}", job.Begin, job.End, job.Id, job.Priority));
            }
    
            Console.WriteLine("\nAssignments:");
            foreach (var assignment in assignments.OrderBy(a => a.Job.Begin).Take(10))
            {
                Console.WriteLine(string.Format("{0}-{1} Id {2} P{3} C{4}", assignment.Job.Begin, assignment.Job.End, assignment.Job.Id, assignment.Job.Priority, assignment.Core));
            }
    
            Console.WriteLine(string.Format("\nTotal Comparisons: {0:n}", Job.Iterations));
    
            Console.WriteLine("Any key to continue");
            Console.ReadKey();
        }
    }
    
    公共类作业
    {
    公共静态长迭代;
    公共int Id;
    公共优先权;
    公共日期时间开始;
    公共日期时间结束;
    公共业务重叠(其他工作)
    {
    迭代++;
    返回this.End>other.Begin&&this.Begina.Job.Begin.Take(10))中的var赋值)
    {
    WriteLine(string.Format(“{0}-{1}Id{2}P{3}C{4}”,assignment.Job.Begin,assignment.Job.End,assignment.Job.Id,assignment.Job.Priority,assignment.Core));
    }
    WriteLine(string.Format(“\n总比较:{0:n}”,Job.Iterations));
    Console.WriteLine(“任何继续键”);
    Console.ReadKey();
    }
    }
    
    样本输出:

    1000个作业x 2个核心
    填充数据
    在0.00ms内完成
    将作业分配给核心
    以7998.00ms完成

    工作:
    2011年1月3日12:00:00 AM-2011年1月3日12:30:00 AM Id 0 P0
    2011年1月3日12:01:00 AM-2011年1月3日12:31:00 AM Id 1 P1
    2011年3月1日12:02:00 AM-2011年3月1日12:32:00 AM Id 2 P2
    2011年1月3日凌晨1:00:00-2011年1月3日凌晨1:30:00 Id 3 P3
    public class Job
    {
        public static long Iterations;
    
        public int Id;
        public int Priority;
        public DateTime Begin;
        public DateTime End;
    
        public bool Overlaps(Job other)
        {
            Iterations++;
            return this.End > other.Begin && this.Begin < other.End;
        }
    }
    
    public class Assignment : IComparable<Assignment>
    {
        public Job Job;
        public int Core;
    
        #region IComparable<Assignment> Members
    
        public int CompareTo(Assignment other)
        {
            return Job.Begin.CompareTo(other.Job.Begin);
        }
    
        #endregion
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            const int Jobs = 1000;
            const int Cores = 2;
            const int ConcurrentJobs = Cores + 1;
            const int Priorities = Cores + 3;
    
            DateTime startTime = new DateTime(2011, 3, 1, 0, 0, 0, 0);
            Console.WriteLine(string.Format("{0} Jobs x {1} Cores", Jobs, Cores));
            var timer = Stopwatch.StartNew();
    
            Console.WriteLine("Populating data");
            var jobs = new List<Job>();
            for (int jobId = 0; jobId < Jobs; jobId++)
            {
                var jobStart = startTime.AddHours(jobId / ConcurrentJobs).AddMinutes(jobId % ConcurrentJobs);
                jobs.Add(new Job() { Id = jobId, Priority = jobId % Priorities, Begin = jobStart, End = jobStart.AddHours(0.5) });
            }
            Console.WriteLine(string.Format("Completed in {0:n}ms", timer.ElapsedMilliseconds));
            timer.Reset();
    
            Console.WriteLine("Assigning Jobs to Cores");
            List<Assignment>[] assignments = new List<Assignment>[Cores];
            for (int core = 0; core < Cores; core++)
                assignments[core] = new List<Assignment>();
    
            Job[] lastJobs = new Job[Cores];
            foreach (Job j in jobs)
            {
                Job job = j;
                bool assigned = false;
                for (int core = 0; core < Cores; core++)
                {
                    if (lastJobs[core] == null || !lastJobs[core].Overlaps(job))
                    {
                        // Assign directly if no last job or no overlap with last job
                        lastJobs[core] = job;
                        assignments[core].Add(new Assignment { Job = job, Core = core });
                        assigned = true;
                        break;
                    }
                    else if (job.Priority > lastJobs[core].Priority)
                    {
                        // Overlap and higher priority, so we replace
                        Job temp = lastJobs[core];
                        lastJobs[core] = job;
                        job = temp; // Will try to later assign to other core
    
                        assignments[core].Add(new Assignment { Job = job, Core = core });
                        assigned = true;
                        break;
                    }
                }
                if (!assigned)
                {
                    // TODO: What to do if not assigned? Your code seems to just ignore them
                }
            }
            List<Assignment> merged = new List<Assignment>();
            for (int core = 0; core < Cores; core++)
                merged.AddRange(assignments[core]);
            merged.Sort();
            Console.WriteLine(string.Format("Completed in {0:n}ms", timer.ElapsedMilliseconds));
            timer.Reset();
    
            Console.WriteLine(string.Format("\nTotal Comparisons: {0:n}", Job.Iterations));
            Job.Iterations = 0; // Reset to count again
    
            {
                IEnumerable<Assignment> assignments2 = null;
                for (int core = 0; core < Cores; core++)
                {
    
    
                    // avoid modified closures by creating local variables
                    int localCore = core;
                    var localAssignments = assignments2;
    
                    // Step 1: Determine the remaining jobs
                    var remainingJobs = localAssignments == null ?
                                                        jobs :
                                                        from j in jobs where !(from a in localAssignments select a.Job).Contains(j) select j;
    
                    // Step 2: Assign the top priority job in any time-slot to the core
                    var assignmentsForCore = from s1 in remainingJobs
                                             where
                                                 (from s2 in remainingJobs
                                                  where s1.Overlaps(s2)
                                                  orderby s2.Priority
                                                  select s2).First().Equals(s1)
                                             select new Assignment { Job = s1, Core = localCore };
    
                    // Step 3: Accumulate the results (unfortunately requires a .ToList() to avoid massive over-joins)
                    assignments2 = assignments2 == null ? assignmentsForCore.ToList() : assignments2.Concat(assignmentsForCore.ToList());
                }
    
                // This is where I'd like to Execute the query one single time across all cores, but have to do intermediate steps to avoid massive-over-joins
                assignments2 = assignments2.ToList();
    
                Console.WriteLine(string.Format("Completed in {0:n}ms", timer.ElapsedMilliseconds));
                Console.WriteLine("\nJobs:");
                foreach (var job in jobs.Take(20))
                {
                    Console.WriteLine(string.Format("{0}-{1} Id {2} P{3}", job.Begin, job.End, job.Id, job.Priority));
                }
    
                Console.WriteLine("\nAssignments:");
                foreach (var assignment in assignments2.OrderBy(a => a.Job.Begin).Take(10))
                {
                    Console.WriteLine(string.Format("{0}-{1} Id {2} P{3} C{4}", assignment.Job.Begin, assignment.Job.End, assignment.Job.Id, assignment.Job.Priority, assignment.Core));
                }
    
                if (merged.Count != assignments2.Count())
                    System.Console.WriteLine("Difference count {0}, {1}", merged.Count, assignments2.Count());
                for (int i = 0; i < merged.Count() && i < assignments2.Count(); i++)
                {
                    var a2 = assignments2.ElementAt(i);
                    var a = merged[i];
                    if (a.Job.Id != a2.Job.Id)
                        System.Console.WriteLine("Difference at {0} {1} {2}", i, a.Job.Begin, a2.Job.Begin);
                    if (i % 100 == 0) Console.ReadKey();
                }
            }
    
    
            Console.WriteLine(string.Format("\nTotal Comparisons: {0:n}", Job.Iterations));
    
            Console.WriteLine("Any key to continue");
            Console.ReadKey();
        }
    }