Поиск сообщества
Показаны результаты для тегов 'ppl'.
Найдено: 4 результата
-
Здравствуйте, коллеги. Пишу метод десериализации для считывания данных из файла и создания соответствующего объекта в памяти. Для того, чтобы пользователь не скучал, загружаю данные в отдельном потоке, а в главном запускаю TAniIndicator. Данные считываются, объект создается, AniIndicator работает. Но при попытке завершения приложения получаю утечку памяти (см. рис.). Пользовательские объекты я удаляю перед закрытием приложения, но в памяти остаются системные объекты, в том числе из библиотеки PPL. Сокращенный код метода загрузки данных ниже. С чем может быть связана утечка? Для детектирования утечек использую команду ReportMemoryLeaksOnShutdown := True. Если дополнительный поток не использую, утечек нет. procedure LoadProjectFromFile(AFileName: string); var fut: IFuture<TComponent>; cmp: TComponent; begin AniIndic.Enabled := True; AniIndic.Visible := True; fut := TTask.Future<TComponent>( function: TComponent begin Result := LoadFromFile(AFileName); end ); TTask.Run( procedure begin fut.Start; cmp := fut.Value; {$REGION 'После загрузки в главном потоке'} TThread.Synchronize(nil, procedure begin AniIndic.Enabled := False; AniIndic.Visible := False; if Assigned(cmp) then begin if cmp is TCAMProject then begin fProject := cmp as TCAMProject; // здесь всякие действия if Assigned(OnFinishedLoadProject) then begin OnFinishedLoadProject(nil); end; end end end ) {$ENDREGION} end ); end;
-
Доброго времени суток. Надеюсь многие пользуются новым средством распараллеливания ITask, подскажите что я делаю с ним не так. Для теста создал простенький класс unit ThreadTask; interface uses System.SysUtils, System.Threading, System.Classes; type TOnCollback = procedure(ID: Integer) of object; TThreadTask = class private Task: ITask; procedure Execute; procedure Print; procedure Close; public OnDestroy: TOnCollback; OnPrint: TOnCollback; Destructor Destroy; override; procedure Start; procedure Stop; end; implementation { TThreadTask } procedure TThreadTask.Close; begin if Assigned(OnDestroy) then OnDestroy(Task.Id); end; destructor TThreadTask.Destroy; begin Stop; TThread.Synchronize(TThread.CurrentThread, Close); inherited; end; procedure TThreadTask.Execute; begin TThread.Sleep(3000); TThread.Synchronize(TThread.CurrentThread, Print); TThread.Sleep(3000); TThread.Synchronize(TThread.CurrentThread, Print); Free; end; procedure TThreadTask.Print; begin if Assigned(OnPrint) then OnPrint(Task.Id); end; procedure TThreadTask.Start; begin Task := TTask.Run(Execute); end; procedure TThreadTask.Stop; begin if Assigned(Task) and (Task.Status = TTaskStatus.Running) then Task.Cancel; end; end. Класс включает в себя интерфейс ITask и после создания и вызова метода Start должен в потоке выполнять какие-то вычисления, в данном случае это просто задержка и вызов коллбека. После отработки класс вызывает коллбек для уведомления о завершении работы и самостоятельно разрушается. Код использования класса: unit Unit1; interface uses ..., ThreadTask; type TForm1 = class(TForm) Memo: TMemo; Button1: TButton; procedure Button1Click(Sender: TObject); private ThreadTask: TThreadTask; procedure TreadDestroy(ID: Integer); procedure TreadPrint(ID: Integer); public { Public declarations } end; var Form1: TForm1; implementation {$R *.fmx} procedure TForm1.Button1Click(Sender: TObject); begin if Assigned(ThreadTask) then FreeAndNil(ThreadTask); ThreadTask := TThreadTask.Create; ThreadTask.OnDestroy := TreadDestroy; ThreadTask.OnPrint := TreadPrint; ThreadTask.Start; end; procedure TForm1.TreadDestroy(ID: Integer); begin Memo.Lines.Add(Format('ThreadTask №%d уничтожен', [ID])); ThreadTask := nil; end; procedure TForm1.TreadPrint(ID: Integer); begin Memo.Lines.Add(Format('Я Task №%d', [ID])); end; end. По нажатию на кнопку проверяем не существует ли предыдущий экземпляр класса, если существует уничтожаем его, создаём новый и запускаем его. Приходящие сообщения от класса выводим в Memo. Если запустить и дождаться полной отработки потоком, то всё ожидаемо, в Memo видим: Я Task №1 Я Task №1 ThreadTask №1 уничтожен Однако если не дождавшись окончания работы первого потока ещё раз нажать на кнопку, то вывод получается совсем не тем, что ожидалось: ThreadTask №1 уничтожен Я Task №2 Я Task №2 Я Task №2 ThreadTask №2 уничтожен Первый класс разрушается, но задача не снимается и кроме того она вызывает лишний раз коллбек от имени второй задачи. Казалось бы можно переписать код кнопки и "занулить" коллбеки: procedure TForm1.Button1Click(Sender: TObject); begin if Assigned(ThreadTask) then begin ThreadTask.OnDestroy := nil; ThreadTask.OnPrint := nil; FreeAndNil(ThreadTask); end; ThreadTask := TThreadTask.Create; ThreadTask.OnDestroy := TreadDestroy; ThreadTask.OnPrint := TreadPrint; ThreadTask.Start; end; Но это не даёт нужного результата, вывод в Memo практически аналогичен предыдущему: Я Task №1 Я Task №1 Я Task №1 ThreadTask №1 уничтожен Может быть Task нельзя так использовать или я что-то делаю не так?
-
Привет. Нуждаюсь в вашем совете. Пару недель назад я начал разрабатывать библиотеку Telegram Bot Api(TelegaPi) для работы с Бот Апи в RAD Studio. И у меня возникла трудность с реализацией отправки запросов на сервер в отдельных потоках(распараллеливание). Например боту нужно отправить фото 100 пользователям. Отправка будет отправляться по очереди от 1 до 100 пользователя. Из-за этого снизится скорость ответа. Можно ли как то в самой библиотеке организовать распараллеливание? Метод отправки фото: function TTelegramBot.sendPhoto(chatId, photo: TValue; caption: string; disable_notification: Boolean; replyToMessageId: Integer; replyMarkup: TtgReplyKeyboardMarkup) : TtgMessage; var Parameters: TDictionary<String, TValue>; begin Parameters := TDictionary<String, TValue>.Create; try Parameters.Add('chat_id', chatId); Parameters.Add('photo', photo); Parameters.Add('caption', caption); Parameters.Add('disable_notification', disable_notification); Parameters.Add('reply_to_message_id', replyToMessageId); Parameters.Add('reply_markup', replyMarkup); Result := API<TtgMessage>('sendPhoto', Parameters); finally Parameters.Free; end; end; Пока что приходи в голову использование iTask<T> - но еще не знаю как бы лучше придумать. Надеюсь на ваши идеи и советы. Спасибо
-
Как можно передать какое-либо значение в ITask? Допустим есть код: procedure TfrmScaner.Switch1Switch(Sender: TObject); var Cursor: uMisc.ICursorChange; Tasks: TArray<ITask>; I: Integer; begin Cursor := TCursorChange.Create(crAppStart); FillGrid; SetLength(Tasks, GridDataManager1.RowCount); // Смотри с этой строки for I := Low(Tasks) to High(Tasks) do Begin Tasks[I] := TTask.Create( Procedure Begin ParseItem(MyParametr); End); Tasks[I].Start; end; end;Мне нужно передать процедуре ParseItem значение MyParametr = I. Как бы это сделать?