Убедительная просьба не пинать, т.к. с такой задачей столкнулся впервые.
И поиск каких то ощутимых ответов не принес.
Возникла необходимость написать нечто наподобие планировщика(именно на здесь возник вопрос).
т.е. необходимо отслеживать время наступления енного количества задач и произвести соответствующее каждой из них действие.
Количество задач заранее неизвестно(может быть и 1 и 500).
Собственно вопрос в том как организовать процесс отслеживания.
Вариант 1. создать для каждой задачи свой Timer.
Но возникает вопрос: сколько таймеров выдержит система? как это отразится на нагрузке?
Вариант 2. создать один таймер и цепочку событий отслеживать по мере наступления времени очередной задачи.
Вариант 3. найти готовый компонент.
Пока пытаюсь решить задачу по 3-му варианту.
Но найти пока не удается.
И есть сомнения: насколько готовая компонента ограничит возможности?
есть ли вообще такие?
И по какому варианту в них реализована обработка?
Хотелось бы услышать мнение коллег имеющих какой то опыт в данном вопросе.
Возможно я просто усложняю задачу, и решение совсем рядом.
U>т.е. необходимо отслеживать время наступления енного количества задач и произвести соответствующее каждой из них действие. U>Количество задач заранее неизвестно(может быть и 1 и 500). U>Вариант 3. найти готовый компонент.
RXTimer из пакета RX компонент.
Работает по второму варианту, описанному Вами.
Программный интерфейс: из кода создаются "виртуальные" таймеры, для программы они выглядят как обычные таймеры — можно выставить интервалы времени и обработчики события OnTimer.
Первый вариант не подходит, так как кол-во таймеров в системе — ресурс очень ограниченный.
Я бы сделал один таймер, но установил его на ближайшее событие.
Перебираем все задачи, находим самую первую по времени. Устанавливаем интервал таймера до этой задачи (время задачи минус текущее время)
Когда задача выполнилась, делаем переопределение интервала по тому же алгоритму.
Также не забываем менять значение интервала при добавлении/удалении/изменении задачи.
Здравствуйте, unga, Вы писали:
U>Возникла необходимость написать нечто наподобие планировщика(именно на здесь возник вопрос). U>т.е. необходимо отслеживать время наступления енного количества задач и произвести соответствующее каждой из них действие. U>Количество задач заранее неизвестно(может быть и 1 и 500).
U>Собственно вопрос в том как организовать процесс отслеживания.
Вот пример простенького планировщика. Надеюсь подойдет в качестве стартовой точки.
type
PCronItem=^TCronItem; // информация о времени запуска задачи. Можно расширить при необходимости.
TCronItem=packed record
Day,Month,Year:word;
Hour,Min,Sec :word;
end;
TOnCronEvent=procedure (Sender:TObject; Item:TCronItem) of object; // обработка момент наступления "времени Ч"
TCron=class(TList) // список времени задач для запускаprivate
FOnCronEvent: TOnCronEvent;
public
procedure AddCron(Item:TCronItem); // добавляем новую задачуprocedure ScanCronItems; // сканируем на предмет "времени Ч"procedure Clear; override; // чистимся Constructor Create; virtual;
property OnCron:TOnCronEvent read FOnCronEvent write FOnCronEvent;
end;
{ TCron }procedure TCron.AddCron(Item: TCronItem);
var P:PCronItem;
begin
New(P);
P^:=Item;
Add(P);
end;
procedure TCron.Clear;
var i:integer;
Item:PCronItem;
begin
for i:=0 to Pred(Count) do
begin
Item:=PCronItem(Self.Items[i]);
if Item=nil then continue;
Items[i]:=nil;
Dispose(Item);
end;
inherited;
end;
constructor TCron.Create;
begin
inherited;
FOnCronEvent:=nil;
end;
function CheckCronItem(Item:TCronItem; AYear,AMonth,ADay,AHour,AMinute,ASecond:word):boolean;
begin
if (Item.Day<>0) and (Item.Month<>0) and (Item.Year<>0) then// если у времени задачи указана дата, то проверяем наступление даты
Result:=(Item.Day=ADay) and (Item.Month=AMonth) and (Item.Year=AYear)
else Result:=True; // если дата не указана - сканируем только времяif Result then
Result:=Result and (Item.Hour<=AHour) and (Item.Min<=AMinute) and (Item.Sec<=ASecond); // время уже наступило end;
procedure TCron.ScanCronItems;
var i:integer;
Item:PCronItem;
AYear,AMonth,ADay,AHour,AMinute,ASecond,AMilliSecond:Word;
begin
DecodeDateTime(Now,AYear,AMonth,ADay,AHour,AMinute,ASecond,AMilliSecond); // хватаем текущее времяfor i:=Pred(Count) downto 0 do
begin
Item:=PCronItem(Items[i]);
if Item=nil then continue;
if CheckCronItem(Item^,AYear,AMonth,ADay,AHour,AMinute,ASecond) then
begin
if Assigned(FOnCronEvent) then FOnCronEvent(Self,Item^); // время !!!
Items[i]:=nil; // раз мы уже обработали этот элемент - он нам больше не нужен
Dispose(Item);
Delete(i);
end;
end;
end;
Ну и соответственно для запуска достаточно в ApplicationEvents.OnIdle() сделать проверку событий и обработать момент наступления события:
var MyCron:TCron; // список задач...Procedure MainForm.HandleCronEvent(Sender: TObject; Item: TCronItem);
begin
FireTimedWork(Item, .....); // тут псевдометод - ну не знаю я, что там за задачи будут запускатсяend;
Procedure MainForm.InitCron; // инициализацияvar CItem:TCronItem;
begin
MyCron:=TCron.Create; // создаем список
MyCron.OnCron:=HandleCronEvent; // устанавливаем обработчик
CItem.Day:=0; CItem.Month:=0; CItem.Year:=0; // нет даты
CItem.Hour:=12; CItem.Min:=0; CItem.Sec:=0; // время 12:00:00
MyCron.AddCron(CItem); // добавляем время срабатывания на "сегодня в 12:00:00"end;
Procedure MainForm.ApplicationOnIdle(Sender: TObject);
begin
MyCron.ScanCronItems; // ждем "времени Ч" когда приложения ничем не занято... Собственно тоже самое можно делать и по таймеру...end;
DM>Procedure MainForm.ApplicationOnIdle(Sender: TObject);
DM>begin
DM> MyCron.ScanCronItems; // ждем "времени Ч" когда приложения ничем не занято... Собственно тоже самое можно делать и по таймеру...
DM>end;
IMHO, лучше вызывать MyCron.ScanCronItems в OnTimer, потому-что после вызова MyCron.ScanCronItems приложение уйдет в цикл ожидания оконного сообщения, которое в теории может не прийти очень долго, и поэтому можно проспать очередной cron.
Здравствуйте, Aniskin, Вы писали:
A>IMHO, лучше вызывать MyCron.ScanCronItems в OnTimer, потому-что после вызова MyCron.ScanCronItems приложение уйдет в цикл ожидания оконного сообщения, которое в теории может не прийти очень долго, и поэтому можно проспать очередной cron.
Ну, в коментариях я это и указал... И OnIdle() приходит тоже достаточно часто. Даже чаще чем OnTimer()
Здравствуйте, Aniskin, Вы писали:
A>IMHO, лучше вызывать MyCron.ScanCronItems в OnTimer, потому-что после вызова MyCron.ScanCronItems приложение уйдет в цикл ожидания оконного сообщения, которое в теории может не прийти очень долго, и поэтому можно проспать очередной cron.
По сути, если задачи отсортировать по времени, то сканировать их и не требуется, требуется только определить, сколько задач уже "созрело" на текущий момент.
Здравствуйте, DarkMaster, Вы писали:
DM>Ну, в коментариях я это и указал...
Термин _можно_ отличается от термина _лучше_
DM>И OnIdle() приходит тоже достаточно часто. Даже чаще чем OnTimer()
Как часто приходят сообщения приложению, если его основное окно скрыто, а таким скорее всего и будет приложение-планировщик? Вероятно, не очень часто, только какие-нибудь служебные (сам я это не проверял, поэтому в случае чего прошу меня поправить). Т.е. если в 20:00 поставить задачу на 20:05 и отлучиться от компьютера, то к 20:05 приложение-планировщик будет находиться в цикле ожидания сообщения, и молоко убежит.
Здравствуйте, DarkMaster, Вы писали:
DM>Здравствуйте, Aniskin, Вы писали:
A>>IMHO, лучше вызывать MyCron.ScanCronItems в OnTimer, потому-что после вызова MyCron.ScanCronItems приложение уйдет в цикл ожидания оконного сообщения, которое в теории может не прийти очень долго, и поэтому можно проспать очередной cron.
DM>Ну, в коментариях я это и указал... И OnIdle() приходит тоже достаточно часто. Даже чаще чем OnTimer()
По перформансу лучше пользоваться такими связками:
Здравствуйте, Aniskin, Вы писали:
DM>>Ну, в коментариях я это и указал... A>Термин _можно_ отличается от термина _лучше_
термин _флейм_ тоже отличается от термина _пример кода_... Все зависит от задачи.
DM>>И OnIdle() приходит тоже достаточно часто. Даже чаще чем OnTimer() A>Как часто приходят сообщения приложению, если его основное окно скрыто, а таким скорее всего и будет приложение-планировщик? Вероятно, не очень часто,
А если не скрыто Давайте начнем гадать на кофейной гуще о структуре приложения и о том, какие задачи нужно запускать по планировщику (про синхронизацию запускаемых задач начинать фантазировать или не надо? Или сразу о потоках поговорим?)...
Я привел код (рабочий) простого планировщика как отправной точки. Методов вызова сканирования списка задач, организации самого списка, информации для списка и т.п. — множество. В дополнение я привел один из примеров использования. В дальнейшем — каждый волен поступать так, как ему будет удобно с приведенным кодом. Или использовать, или выбросить, или доработать напильником.