Я пытаюсь создать свой собственный планировщик задач C #, поэтому, например, я хочу запускать определенный void с аргументом Id каждый понедельник недели.Я также хочу сохранить список всех запущенных задач для каждого планировщика.
Таким образом, у вас будет планировщик, который содержит список задач, и эти задачи имеют действия и триггеры, действия - это метод (ы), который я хочувыполнять и запускать, например, каждый понедельник каждой недели.
Теперь, когда задача выполнена и она достигла своей конечной даты, она должна в значительной степени распоряжаться собой, как будто ее никогда не существовало.Здесь я не знаю, что делать дальше.
Сейчас это крайний пример, но я попытался составить расписание для одного миллиона задач, которые будут выполняться через 10 секунд.Все задачи выполнялись, но как-то не были правильно расположены.Visual Studio сообщает, что объем памяти процесса составляет около 700 МБ, а памяти кучи - около 2 МБ после выполнения задач.
Я попробовал две вещи:
Сброссистема, которая запускается каждые 30 секунд и буферизует завершенные задачи и удаляет их из списка, а затем из буфера.Это сработало отчасти, после запуска миллиона задач мне бы выдалось исключение «Коллекция была изменена».
Самоораспределение задач, когда задача будет завершена, она избавится от себя.При выполнении этого с сотней тысяч задач он избавился бы от большинства из них и удалил бы их из списка, но у меня было по крайней мере пять тысяч задач в списке задач.
Мой вопрос заключается в том, какправильно ли я правильно и надежно располагаю задачи и удаляю их из списка задач, чтобы они больше не существовали в памяти без получения каких-либо исключений, таких как «Коллекция была изменена».
Вот мой код, который я использовалВам, возможно, придется немного отредактировать его, чтобы использовать в нем систему сброса и самоуничтожающуюся систему.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Timers;
using static TaskScheduler.Scheduler;
namespace TaskScheduler
{
internal class Program
{
public static void Main(string[] args)
{
Scheduler scheduler = new Scheduler(new TimeSpan(0, 0, 30));
for (int i = 0; i < 100000; i++)
{
scheduler.Schedule(Function, new Settings() { Id = i, Start = DateTime.Now.AddSeconds(10) });
}
scheduler.Schedule(Function, new Settings() { Id = 1123, Recurring = true, Start = DateTime.Now.AddSeconds(5), End = DateTime.Now.AddDays(14) });
while (true)
{
Console.WriteLine(scheduler.Tasks.Count());
System.Threading.Thread.Sleep(500);
}
}
public static void Function(Task task)
{
Console.WriteLine($"Test function: {task._settings.Id}");
}
}
public class Scheduler : IDisposable
{
public List<Task> Tasks = new List<Task>();
public List<Task> FlushCollection = new List<Task>();
private Timer timer; //Flush timer
public Scheduler(TimeSpan time)
{
timer = new Timer(time.TotalMilliseconds);
timer.Elapsed += new ElapsedEventHandler(Flush);
timer.Start();
}
public void Flush(object sender, ElapsedEventArgs args)
{
foreach (Task task in Tasks.ToArray())
{
if (task.timer == null)
{
FlushCollection.Add(task);
}
}
foreach(Task task in FlushCollection.ToArray())
{
Tasks.Remove(task);
}
FlushCollection.Clear();
}
public void Schedule(Action<Task> action, Settings settings)
{
Tasks.Add(new Task(this, action, settings));
}
public void Unschedule(Task task)
{
task.Dispose();
Tasks.Remove(task);
}
public void Unschedule(int id)
{
Unschedule(Tasks.Where(x => x._settings.Id == id).FirstOrDefault());
}
public void Dispose()
{
foreach (Task task in Tasks.ToArray())
{
task.Dispose();
}
Tasks.Clear();
}
public class Task : IDisposable
{
public Scheduler _scheduler;
public Action<Task> _action;
public Settings _settings;
public Timer timer;
private DateTime next;
public Task(Scheduler scheduler, Action<Task> action, Settings settings)
{
_scheduler = scheduler;
_action = action;
_settings = settings;
Init();
}
public void Init()
{
next = DateTime.Now + _settings.Interval;
timer = new Timer((_settings.Start - DateTime.Now).TotalMilliseconds);
timer.Elapsed += new ElapsedEventHandler(Elapsed);
timer.Start();
if (_settings.Interval.TotalMilliseconds != 0)
{
timer.Interval = _settings.Interval.TotalMilliseconds;
}
}
public void Elapsed(object sender, ElapsedEventArgs args)
{
if (!Ready())
{
return;
}
Run();
}
public void Dispose()
{
timer.Dispose();
timer = null;
}
public bool Ready()
{
return DateTime.Now >= next;
}
public void Run()
{
_action(this);
if (Expired() || !_settings.Recurring)
{
_scheduler.Unschedule(this);
}
}
public bool Expired()
{
if (DateTime.Now >= _settings.End)
{
return true;
}
return false;
}
}
public class Settings
{
public int? Id { get; set; }
public bool Recurring { get; set; } = false;
public TimeSpan Interval { get; set; } //Not required when not recurring.
public DateTime Start { get; set; } = DateTime.Now;
public DateTime End { get; set; } = DateTime.Now.AddTicks(1);
}
}
}
Имейте в виду, что это всего лишь прототип, поэтому он не содержит всего триггера и действияСистема еще и другие вещи, которые я упомянул.