Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2003.12.26;
Скачать: [xml.tar.bz2];

Вниз

Работа с потоками   Найти похожие ветки 

 
real_dimedrol   (2003-12-11 18:58) [0]

Есть процедура с циклом, которая выполняется отдельным потоком.
Выполняется долго. Есть форма в приложении, которая должна выводить статистику работы цикла. Статистика собирается по таймеру.
Проблема: каждый раз, когда срабатывает ontimer, поток с циклом теряет управление на некоторое время, потом продолжает работу. Как можно этого избежать? Т.е. минимизировать время, на которое управление передается главному процессу.
Пример такой задачи - копирование больших файлов. Когда выводится скорость копирования, оставшееся время и проч.
Таймер нужен по-любому!!!


 
Юрий Зотов   (2003-12-11 19:18) [1]

1. А так ли уж нужен таймер?
2. Зачем дополнительному потоку вобще терять управление?

Дополнительный поток периодически вызывает PostMessage (но не SendMessage) и отсылает форме сообщение с нужной информацией (а сам продолжает свою работу). Получив это сообщение, форма обновляет статистику. Все.


 
jack128   (2003-12-11 19:18) [2]


> поток с циклом теряет управление на некоторое время
не понял этой фразы.. Что означает "теряет управление"??


 
panov   (2003-12-11 19:26) [3]

>jack128 © (11.12.03 19:18) [2]
> поток с циклом теряет управление на некоторое время
не понял этой фразы.. Что означает "теряет управление"??


Это означает, что система переключается на выполнение другого потока.

>Юрий Зотов © (11.12.03 19:18) [1]

1. А так ли уж нужен таймер?
Конечно, нуже не таймер, а то, что написано после п.2 -
Дополнительный поток периодически вызывает PostMessage (но не SendMessage) и отсылает форме сообщение с нужной информацией (а сам продолжает свою работу). Получив это сообщение, форма обновляет статистику. Все.

2. Зачем дополнительному потоку вобще терять управление?

При необходимости обновлять визуальные компоненты в другом потоке в любом случае доп.поток будет "терять управление" для того, чтобы эти данные отобразить, даже если вочпользоваться советом из п.2.

Другое дело, что способ с PostMessage позволит минимизировать потери времени, так как само использование таймера тоже приводит к непроизводительной работе.


 
jack128   (2003-12-11 19:29) [4]

Вообще говоря поток "теряет управление" даже без обнавления контролов и тп. Иначе мы бы не имели никакой многозадачности и многопоточности...


 
jack128   (2003-12-11 19:30) [5]

о многопроц. системах речи нет, ессесено..


 
panov   (2003-12-11 19:31) [6]

>jack128 © (11.12.03 19:29) [4]

Конечно, но при переключении по инициативе приложения накладные расходы еще увеличиваются...


 
real_dimedrol   (2003-12-12 00:43) [7]

Юрий Зотов ©
Хорошо, нужно каждую секунду пересчитывать скорость выполнения операций. Конечно, можно после каждой итерации цикла (после двух, трех...) обновлять статистику, но... а вдруг некоторая итерация работает 10 минут??? И за это время статистика обновлятся не будет. Как отправлять сообщение каждые n милисек. без таймера? Из потока.
По-любому при событии тамера управление передается из потока в первичный поток, потому что... хрен знает почему. Хотя, потому что первичный поток создавал таймер и обрабатывает его сообщения. Процедурка из потока запускается без Synchronize, так что первичный поток реагирует на сообщения.
Вобщем, я пока так и не понял, как мне поступить.


 
jack128   (2003-12-12 01:00) [8]

Я так и не понял, кто собирает стат-ку о потоке - он сам о себе или все таки осн. поток останавливает доп. поток собирает информацию, а потом запускает снова? Или основной поток не останавливает допол. поток и операция thread-safe???


 
sniknik   (2003-12-12 01:10) [9]

> Процедурка из потока запускается без Synchronize, так что первичный поток реагирует на сообщения.
> Вобщем, я пока так и не понял, как мне поступить.
исправить немедленно! без синхронизации да еше и с отрисовкой на главной форме(как статистику показываеш? не в этой процедуре?) это не только к тормозам но и к глюкам.

(не помешали бы дополнительные пояснения что и как делаеш, пояснения желательно перемежать кодом)


 
real_dimedrol   (2003-12-12 03:19) [10]

sniknik
На форме, на которой все рисуется, лежит таймер, который собственно и работает со статистикой. Если включить синхронизацию, то во время работы процедуры с циклом эта форма не реагирует на сообщения (висит, практически) и таймер, естественно, не работает, а вызвать нечто вроде sleep из процедуры, вызванной как synchronize - не дает эффекта. Вобщем, что хотелось бы я обрисовал. Еще раз вкратце: нужно каждую секунду обрабатывать статистику, накапливаемую потоком, и выводить ее на форму.
jack128:
Статистику накапливает вторичный поток. Первичный поток по таймеру ее обрабатывает, что выходит очень криво.


 
Юрий Зотов   (2003-12-12 09:21) [11]

> real_dimedrol

> а вдруг некоторая итерация работает 10 минут??? И за это
> время статистика обновлятся не будет.

Если она за эти 10 минут реально не изменилась, то зачем ее обновлять? Хоть обновляй, хоть не обновляй - все равно то же самое и покажет.

А если изменилась, то сразу после ее изменения второй поток отправляет сообщение форме, и та обновляет отображение статистики.

> Как отправлять сообщение каждые n милисек. без таймера? Из
> потока.

Не "каждые n миллисек.", а при каждом реальном изменении статистики. Зачем нужно обязательно обновлять ее именно раз в секунду? А если она в течение 5 секунд не меняется? Ну, нарисуем 5 раз одно и то же - только лишняя работа получится. Обновлять надо не по времени, а при каждом реальном изменении.

В общем, примерно так (на примере копирования списка файлов, хранящегося в TMemo).

const
AM_UPDATE = WM_USER + 100;

type
TFileCopyThread = class(TThread)
private
FFileList: TStrings;
FTargetDir: string;
FForm: TForm;
protected
procedure Execute; override;
public
constructor Create(FileList: TStrings; TargetDir: string; Form: TForm); overload;
end;

TFileCopyForm = class(TForm)
FileListMemo: TMemo; // Заполнить списком файлов
ProgressBar: TProgressBar; // Выставить Smooth = True
StartButton: TButton; // OnClick = StartButtonClick
procedure StartButtonClick(Sender: TObject);
protected
procedure UpdateInfo(var Message: TMessage); message AM_UPDATE;
end;

constructor TFileCopyThread.Create(FileList: TStrings; TargetDir: string; Form: TForm);
begin
inherited Create(True);
FreeOnTerminate := True;
FFileList := FileList;
FTargetDir := IncludeTrailingBackSlash(TargetDir);
FForm := Form;
Resume
end;

procedure TFileCopyThread.Execute;
var
i: integer;
begin
for i := 0 to FFileList.Count - 1 do
begin
CopyFile(PChar(FFileList[i]), PChar(FTargetDir + ExcludeFileName(FFileList[i])), False);
PostMessage(FForm.Handle, AM_UPDATE, i, 0)
end;
end;

procedure TFileCopyForm.StartButtonClick(Sender: TObject);
var
Dir: string;
begin
if SelectDirectory("Выберите каталог", "", Dir) then
with FileListMemo, ProgressBar do
begin
Max := Lines.Count - 1;
TFileCopyThread.Create(Lines, Dir, Self)
end
end;

procedure TFileCopyForm.UpdateInfo(var Message: TMessage);
begin
ProgressBar.Position := Message.WParam
end;

И все. И никаких таймеров. И неважно, сколько времени занимает копирование каждого отдельного файла - секунду или минуту. Как только его скопировали - так тут же и обновили информацию. А пока его еще не скопировали - зачем ее обновлять, если она еще реально не изменилась? Все равно нарисуется то же самое.


 
real_dimedrol   (2003-12-12 13:58) [12]

Юрий Зотов ©
Понял вашу идею. Видимо, так придется и работать. Хотя в ней изначально заложен "дефект". Представьте себе, как будет выглядеть копирование файла в 700мб (а ведь часто, однако, приходится такие фалы копировать) при помощи этого потока... 30 секунд никакой реакции от формы, а потом - клац - и 100%. Вы видели где-нибудь такую индикацию копирования? Конечно, можно еще копировать блочно, stream-но, еще как-нибудь, для более коротких итераций, но far, например, может юзать именно CopyFile(use windows file copy routines) и при этом прекрасно отображает динамику копирования, включая скорость.

Если она за эти 10 минут реально не изменилась, то зачем ее обновлять? Хоть обновляй, хоть не обновляй - все равно то же самое и покажет.

Ох и не то же самое. Если за последние пять минут не было выполнено ни одной итерации, то уже 300 секунд как скорость работы 0 итераций в секунду, а юзверь между тем все еще видит какую-то "старую" скорость. Контрпример - флэшгет. До получения очередного пакета, используя описанный вами способ, он будет показывать некоторую одну и ту же скорость закачки (совсем не обязательно 0) а пакета он может ждать долго....


 
Romkin   (2003-12-12 14:04) [13]

Сначала я бы посоветовал разобраться, для чего нужно вызывать Syncronize ;)
А контрпример не катит, там таймер работает с данными, уже находящимися в распоряжении основного потока, сколько скачано.скока время. А вот скока скачано - сообщает собственно поток скачивания.


 
Erik   (2003-12-12 14:08) [14]

Вобщето тебе лучше всего воспользоватся функциями explorer. SHLCopy.... чтото в этом роде он сам показывает сколько скопировано.


 
Юрий Зотов   (2003-12-12 14:14) [15]

> real_dimedrol (12.12.03 13:58) [12]

> Вы видели где-нибудь такую индикацию копирования?
Видел. При инсталляции Windows, например.

Еще существуют "итерационные" алгоритмы подстройки прогрессбара (например, когда Max заранее неизвестно и постоянно уточняется уже в самом процессе).


 
Юрий Зотов   (2003-12-12 14:18) [16]

> real_dimedrol (12.12.03 13:58) [12]

Только не "клац - и 100", а и плавное перемещение прогресбара на одну единицу за один шаг. У него же Max - это количество файлов, а не их общий размер.


 
real_dimedrol   (2003-12-13 02:35) [17]

Юрий Зотов ©
А если файл всего один? Клац - и сто!

All
Ладно, мы дошли до той точки, когда начинается уже флейм.
Спасибо всем за помощь. Как минимум, картину возможных действий я себе уже обрисовал. А копирование файлов вообще ни при чем. Это для примера.


 
Igorek   (2003-12-13 11:39) [18]

Проще всего, когда код из потока имеет доступ к контролам на форме. Тогда он сам может обновить положение прогресс бара. Без всяких мессаг, напрямую. Кроме того советую обновлять прогресс бар по информации, которая более плавно изменяется во времени. При копировании - обьем информации. Ессно сначала надо посчитать суммарный обьем.


 
Юрий Зотов   (2003-12-13 12:51) [19]

> Igorek © (13.12.03 11:39) [18]

Вот именно ЭТОГО делать и не следует. Потому что обновление визуальных контролов связано с вызовом Synchronize, а тогда исчезает смысл второго потока.



Страницы: 1 вся ветка

Форум: "Основная";
Текущий архив: 2003.12.26;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.51 MB
Время: 0.007 c
1-86440
Jelet
2003-12-12 17:20
2003.12.26
отобразить RTF


3-86248
Василий
2003-12-03 02:44
2003.12.26
Как программно создать файл базы данных FireBird ?


1-86406
Spotter
2003-12-14 18:43
2003.12.26
Обработка onKeyDown в TRxRichEdite


3-86321
Russko
2003-12-01 13:41
2003.12.26
Table is busy


4-86594
Dark Elf
2003-10-30 13:06
2003.12.26
Использование dll в Дельфи





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский