TPL architectural question

后端 未结 2 1051
甜味超标
甜味超标 2021-02-06 09:48

I\'m currently working on a project, where we have the challenge to process items in parallel. So far not a big deal ;) Now to the problem. We have a list of IDs, where we perio

2条回答
  •  醉话见心
    2021-02-06 10:27

    This is pretty similar to the approach you said you already had in your question, but does so with TPL tasks. A task just adds itself back to a list of things to schedule when its done.

    The use of locking on a plain list is fairly ugly in this example, would probably want a better collection to hold the list of things to schedule

    // Fill the idsToSchedule
    for (int id = 0; id < 5; id++)
    {
        idsToSchedule.Add(Tuple.Create(DateTime.MinValue, id));
    }
    
    // LongRunning will tell TPL to create a new thread to run this on
    Task.Factory.StartNew(SchedulingLoop, TaskCreationOptions.LongRunning);
    

    That starts up the SchedulingLoop, which actually performs the checking if its been two seconds since something ran

    // Tuple of the last time an id was processed and the id of the thing to schedule
    static List> idsToSchedule = new List>();
    static int currentlyProcessing = 0;
    const int ProcessingLimit = 3;
    
    // An event loop that performs the scheduling
    public static void SchedulingLoop()
    {
        while (true)
        {
            lock (idsToSchedule)
            {
                DateTime currentTime = DateTime.Now;
                for (int index = idsToSchedule.Count - 1; index >= 0; index--)
                {
                    var scheduleItem = idsToSchedule[index];
                    var timeSincePreviousRun = (currentTime - scheduleItem.Item1).TotalSeconds;
    
                    // start it executing in a background task
                    if (timeSincePreviousRun > 2 && currentlyProcessing < ProcessingLimit)
                    {
                        Interlocked.Increment(ref currentlyProcessing);
    
                        Console.WriteLine("Scheduling {0} after {1} seconds", scheduleItem.Item2, timeSincePreviousRun);
    
                        // Schedule this task to be processed
                        Task.Factory.StartNew(() =>
                            {
                                Console.WriteLine("Executing {0}", scheduleItem.Item2);
    
                                // simulate the time taken to call this procedure
                                Thread.Sleep(new Random((int)DateTime.Now.Ticks).Next(0, 5000) + 500);
    
                                lock (idsToSchedule)
                                {
                                    idsToSchedule.Add(Tuple.Create(DateTime.Now, scheduleItem.Item2));
                                }
    
                                Console.WriteLine("Done Executing {0}", scheduleItem.Item2);
                                Interlocked.Decrement(ref currentlyProcessing);
                            });
    
                        // remove this from the list of things to schedule
                        idsToSchedule.RemoveAt(index);
                    }
                }
            }
    
            Thread.Sleep(100);
        }
    }
    

提交回复
热议问题