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

Вниз

Увеличится ли скорость в моём случае если я сделаю 2 потока?   Найти похожие ветки 

 
rolex   (2005-03-08 18:45) [0]

Моя прога предположим ищет файлы на винте. Увеличится ли скорость общего поиска, если я его разобью на 2 потока?


 
Anatoly Podgoretsky ©   (2005-03-08 18:47) [1]

Уменьшится и возможно сильно. Операция перемещения головок очень медленная.


 
Antonn ©   (2005-03-08 18:51) [2]

Может мелось ввиду, что поиск будет идти во втором потоке, а в первом интерфейсная часть? Думаю, прога работать будет быстрее.


 
Anatoly Podgoretsky ©   (2005-03-08 19:04) [3]

И в этом случае разницы не заметить, Операция перемещения головок очень медленная и остальные файловые функции не блещут скоростью. Потоки будут просто простаивать, но все равно потребуется дополнительное время на синхронизацию.


 
Набережных С. ©   (2005-03-08 19:06) [4]


> Anatoly Podgoretsky ©   (08.03.05 18:47) [1]

Ну почему обязательно так? Если винт использует ПДП, а сейчас трудно найти не такой, то скорость увеличится. Тем более, что и процессоров может быть несколько. Разумеется, при грамотной организации всего процесса.


 
rolex   (2005-03-08 19:07) [5]


> Anatoly Podgoretsky ©   (08.03.05 18:47) [1]
> Уменьшится и возможно сильно. Операция перемещения головок
> очень медленная.

А как тогда увеличить скорость поиска?


> Antonn ©   (08.03.05 18:51) [2]
> Может мелось ввиду, что поиск будет идти во втором потоке,
> а в первом интерфейсная часть? Думаю, прога работать будет
> быстрее.

Да нет. У меня в процедуре поиска Application.ProcessMessages через каждую строчку понатыкано, поэтому прога у меня не тормозит.


 
rolex   (2005-03-08 19:09) [6]


> Набережных С. ©   (08.03.05 19:06) [4]
>
> > Anatoly Podgoretsky ©   (08.03.05 18:47) [1]
>
> Ну почему обязательно так? Если винт использует ПДП, а сейчас
> трудно найти не такой, то скорость увеличится. Тем более,
> что и процессоров может быть несколько. Разумеется, при
> грамотной организации всего процесса.

Неет... :)) Процессор один. А прога рассчитана на стандартный домашний комп. А что такое "ПДП"? Ниразу не слышал о такой технологии.


 
Anatoly Podgoretsky ©   (2005-03-08 19:10) [7]

rolex   (08.03.05 19:07) [5]
Грамотным построение программы, но увеличить практически невозможно, диски это медленное устройство. Кешируй, не ищи во всю глубину, используй предсказания и так далее.


 
Antonn ©   (2005-03-08 19:19) [8]


> ПДП

DMA?


 
Набережных С. ©   (2005-03-08 19:20) [9]


> rolex   (08.03.05 19:09) [6]

ПДП - прямой доступ к памяти, DMA по-нынешнему. Например, один поток занимается обменом с диском, второй собственно обработкой. Пока первый ждет, второй много что успеет сделать. Да и первый можно занять, пока идет обмен с диском.


 
Anatoly Podgoretsky ©   (2005-03-08 19:23) [10]

Набережных С. ©   (08.03.05 19:20) [9]
Ну ему то не это надо ускорить, не паралельные вычисления, а поиск на диске. Тут два потока дадут замедление из-за постоянного движения головок туда сюда.


 
Набережных С. ©   (2005-03-08 19:27) [11]

Переключение потоков конечно время займет, но NT - не 9х, тут это довольно шустро. Я как-то делал кучу тестов, так на достаточно длительной операции разницы между выполнением ее одним потоком или несколькими, практически нет, в пределах погрешности измерений.


 
Набережных С. ©   (2005-03-08 19:32) [12]


> Anatoly Podgoretsky ©   (08.03.05 19:23) [10]

Ну а поиск что? Считал пару десятков мег и обрабатывай, а в это время считывай следующую пару десятков. Да и процессоры с HT все больше распространяются. Нет, я думаю, надо учитывать возможность многопроцессорности, программа должна уметь подстраиваться. Конечно, придется попотеть с организацией, но, имхо, попробовать стоит.


 
Anatoly Podgoretsky ©   (2005-03-08 19:33) [13]

Набережных С. ©   (08.03.05 19:32) [12]
Смотри 7


 
Набережных С. ©   (2005-03-08 19:35) [14]


> Anatoly Podgoretsky ©   (08.03.05 19:33) [13]

Совершенно согласен. Но одно другого, имхо, не отменяет.


 
Anatoly Podgoretsky ©   (2005-03-08 19:48) [15]

Набережных С. ©   (08.03.05 19:35) [14]
Вот когда будет другая предпосылка, чем в данном вопросе, тогда можно будет и о другом поговорить, а в данной постановке замедление и снижение надежны работы, из-за уровня знаний.


 
Набережных С. ©   (2005-03-08 19:53) [16]


> Anatoly Podgoretsky ©   (08.03.05 19:48) [15]
>  а в данной постановке замедление и снижение надежны работы,
> из-за уровня знаний.

:)))


 
Sphinx ©   (2005-03-08 20:13) [17]

А может попробовать использовать службу индексирования в NT-системах...или она только в ХР есть...или тольно на NTFS...запамятовал...???
Но включение индексирования действительно ускоряет поиск...


 
rolex   (2005-03-08 21:01) [18]


> Sphinx ©   (08.03.05 20:13) [17]
> А может попробовать использовать службу индексирования в
> NT-системах...или она только в ХР есть...или тольно на NTFS...запамятовал...???
> Но включение индексирования действительно ускоряет поиск...

Поподробнее пожалуйста...


 
Дмитрий Мыльников   (2005-03-08 21:02) [19]

А в чём, собственно, заключается поиск-то? Если просто по имени файла в файловой системе, то тут основную работу будет делать OC, так что многопоточность ничего не даст. Если же производится ещё и анализ внутренних данных в самих файлах, то тогда многопоточность при небольшом количестве потоков может ускорить работу программы. Пока один поток получает данные, другие будут заняты анализом.

Что же касается кэширования, то мне кажется, что в данном случае это не сильно поможет, поскольку кэширование даёт выигрыш при многократном обращении к одним и тем же данным, что нехарактерно для поиска.


 
rolex   (2005-03-08 21:06) [20]


> ...Если просто по имени файла в файловой системе...

Именно это и делает моя программа.
Т.е. по вашим словам FindFirst и FindNext - быстрее уже ничего нереально сделать. Так?


 
Erik1 ©   (2005-03-09 11:15) [21]

В отдельный поток всеравно стоит вынести и отделить от нитерфейсной части. Структура программы станент более правильной и Application.ProcessMessage ненадо будет тыкать везде где возможно. А вобще еденичный поиск происходит относительно быстро, в ускорении процеса тебе может помочь другая логическая организация. Попробуй полностью изложить постаноыку задачи.


 
rolex   (2005-03-09 13:03) [22]

Аааа.... столько текста набирал!!! Всё стёрлось! Заново писать уже сил нету. Короче вот процедура поиска (выдрал прямо из исходников без изменения), если разберётесь конечно:
procedure ScanDrive(const DirName, Mask :String);
 procedure ScanDirs(const DirName :String);
 var
   h   :tHandle;
   wfd :tWin32FindData;
   s,i,iskl:integer;
   sizeDir:TLargeInteger;
 begin
 Application.ProcessMessages;
 form1.Label2.Caption:="Поиск в "+DirName;
   h := Windows.FindFirstFile(PChar(DirName+Mask), wfd);
   try
     if (h<>INVALID_HANDLE_VALUE) and (Not((DirName=Form2.Edit1.Text)and(Form2.RadioButton3.Checked=True))) then begin
       repeat
         Application.ProcessMessages;
         if  ((wfd.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY)=0) then begin
           for s:=0 to Form2.CheckListBox2.Count - 1 do begin
             Application.ProcessMessages;
             if (Form2.CheckListBox2.Checked[s]) and (Form1.FScanAborted=false) and (MatchesMask(wfd.cFileName, Form2.CheckListBox2.Items[s])=true) and (HaveCopyItem(DirName+wfd.cFileName)=False) then
             if (MatchesMask(wfd.cFileName, Form2.CheckListBox2.Items[s]))=true then //-- Двойная проверка
             begin
               iskl:=0; //-- Проверка на исключения
               for i:=0 to Form2.ListBox1.Count-1 do if (MatchesMask(wfd.cFileName, Form2.ListBox1.Items[i]))=true then begin iskl:=1; if HaveCopyItemOnExclusion(DirName+wfd.cFileName)<>true then with Form5.ListView1.Items.Add do begin Caption:=DirName+wfd.cFileName; SubItems.Add(Form2.CheckListBox2.Items[s]); SubItems.Add(Form2.ListBox1.Items[i]); end; end;
               if iskl<>1 then
               begin
               form1.CheckListBox1.Items.Add(DirName+wfd.cFileName);
               chetchik:=chetchik+1;
               Form1.label14.Caption:=IntToStr(StrToInt(Form1.label14.Caption)+1);
               fsize:=fsize+GetFileSize(DirName+wfd.cFileName);
               ToShowSize;
               end else Form1.label1.Caption:=IntToStr(StrToInt(Form1.label1.Caption)+1);
             end;
           end;
         foundedsize:=foundedsize+GetFileSize(DirName+wfd.cFileName);
         form1.ProgressBar1.width:=((form1.Width-12)div 100)*(100*foundedsize div allsize+1);
         form1.Image9.Left:=form1.ProgressBar1.width+form1.ProgressBar1.left;
         end;
       until  (not Windows.FindNextFile(h,wfd)) or (Form1.FScanAborted=true);
     end else if (DirName=Form2.Edit1.Text)and(Form2.RadioButton3.Checked=True) then begin SizeDir:=0; GetDirSize(DirName, SizeDir); foundedsize:=foundedsize+SizeDir; end;
   finally
     if  h <> INVALID_HANDLE_VALUE  then Windows.FindClose(h);
   end;
   Application.ProcessMessages;
   // Теперь рекрсивно просмотрим подкаталоги
   h := Windows.FindFirstFile(PChar(DirName+"*.*"), wfd);
   try
   Application.ProcessMessages;
     if  h <> INVALID_HANDLE_VALUE  then begin
       repeat
         Application.ProcessMessages;
         if   ((wfd.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) <> 0)
          and (wfd.cFileName <> String("."))
          and (wfd.cFileName <> "..")           then
           ScanDirs(IncludeTrailingPathDelimiter(DirName+wfd.cFileName));
           Application.ProcessMessages;
       until  (not Windows.FindNextFile(h,wfd)) or (Form1.FScanAborted=true) or (Application.Terminated);
     end;
   finally
     if  h <> INVALID_HANDLE_VALUE  then Windows.FindClose(h);
   end;
 end;
begin // FindFilesByMask
 ScanDirs(IncludeTrailingPathDelimiter(DirName));
 Application.ProcessMessages;
end;


 
raidan ©   (2005-03-09 13:13) [23]

Увеличить скорость можно, если есть несколько дисков как физических устройств и читать параллельно с них. Хотя это уже извращения. Кому нужна большАя скорость - тот сделает себе RAID-0.


 
Digitman ©   (2005-03-09 13:40) [24]


> Application.ProcessMessages через каждую строчку понатыкано


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

оптимизируй свой алгоритм, удалив множественные явные именованые обращения к одним и тем же идентификаторам, используя взамен этого оператор with - будет дополнительное увеличение сквозной производительности

минимизируй строковые операции - будет тебе приращение той же произв-ти за счет меньшего числа перераспределений памяти встроенным менеджером памяти

да мало ли чего еще тут можно оптимизировать ! ... судя по коду - просто поле непаханое ..

в конце-концов - переделать алгоритм целиком, читая каталоговую структуру однократно, а затем фиксируя лишь события ее изменения


 
Erik1 ©   (2005-03-09 15:39) [25]

И рекурсию можно убрать, тоже производительность увеличится( http://www.codenet.ru/progr/other/prbook/gl8.php )


 
rolex   (2005-03-09 16:56) [26]


> не "тыкай" сабж где ни попадя - будет тебе существенное
> увеличение сквозной производительности

А где лишние Application.ProcessMessages в моём коде???


> оптимизируй свой алгоритм, удалив множественные явные именованые
> обращения к одним и тем же идентификаторам, используя взамен
> этого оператор with - будет дополнительное увеличение сквозной
> производительности

Т.е. это значит в, например, коде:
Form1.width:=...;
form1.height:=...;
form1.title:=...;
Мне нужно сделать так:
with Form1 do
begin
width:=...;
height:=...;
title:=...;
end;

я так понял?


> минимизируй строковые операции - будет тебе приращение той
> же произв-ти за счет меньшего числа перераспределений памяти
> встроенным менеджером памяти

Не понял... можно по подробнее.


> в конце-концов - переделать алгоритм целиком, читая каталоговую
> структуру однократно, а затем фиксируя лишь события ее изменения

Это я тоже не понял. Объясните плз!!!


 
Дмитрий Мыльников   (2005-03-09 21:49) [27]

Ну на счёт всякой оптимизации через with и прочее, это когда явные тормоза уберёшь. А так особо и не заметишь. :)

Во-первых, как уже было сказано, не нужно Application.ProcessMessages вызывать в каждом повторении цикла. Заведи счётчик, и в конце цикла напиши что-то типа

int(I);
if (i mod 100) = 0 then Application.ProcessMessages;
То есть, вызывай его один раз на 100 проходов цикла (оптимальное число подбирается путём натурных испытаний). Плюс, в конце функции тоже можно, поскольку она у тебя рекурсивная.
Кстати, от рекурсии я бы не стал отказываться, поскольку так код выглядит проще, а существенного ускорения на древовидной структуре всё равно с помощью других алгоримтов не получить. Зато код будет более сложным.

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

<компонент>.Items.BeginUpdate;
try
  ... тут вносим массовые изменения в Items
finally
  <компонент>.Items.EndUpdate;
end;

Фишка в том, что после вызова BeginUpdate блокируется вызов обновления компонента на экране до тех пор, пока не будет вызвана EndUpdate, которая и отобразит все изменения сразу. А сейчас у тебя получается, что каждое добавление строки запускает весьма длительный код по обновлению компонента на экране.


 
Knight ©   (2005-03-09 22:24) [28]

На собственном опыте убедился, что всякие там Application.ProcessMessages и ProgressBar"ы, тормозят процесс в несколько раз... чем реже, тем быстрее... :)


 
Fay ©   (2005-03-09 22:43) [29]

Что-то не верится, что with-ом можно ускорить поиск.


 
rolex   (2005-03-10 12:28) [30]

Вернёмся к потокам.
Вот схема (по моим предположениям):
1) Сейчас прога так сканирует:
Сканирование  |- - - - |
Др. обработка | - - - -|


2) Если сделать 2потока (1й на скан, 2й на др. обработку):Сканирование  |---- |
Др. обработка | ----|


Т.е. в первом случае сканируется файл, прога ждёт; потом прога смотрит (проверяет) файл, "сканирование" ждёт.

Во втором случае, всё идёт параллельно и нету практически никаких ожиданий, ни с той стороны, ни с другой.

Вывод: Во втором случае времени на общее сканирование (включая обработку) потребуется времени почти в два раза меньше!

*Под обработкой понимается сверка имения файла со списком масок и т.д.

Правильны ли мои рассуждения???


 
Digitman ©   (2005-03-10 13:33) [31]


> rolex   (08.03.05 18:45)  
> Моя прога предположим ищет файлы на винте


ну и пусть себе ищет !
зачем каждый найденный файл тут же изображать юзеру ? вот это непонятно ..

ну сформируй ты данные все разом, а потом изобрази их юзеру готовыми ! зачем рисовать по одному элементу за одну итерацию-то ? вот это непонятно ..


 
Erik1 ©   (2005-03-10 13:43) [32]

to rolex
Твои расждения правильны, если обработка занимает хотябы 500mc. К томуже такой подход позволит привести в порядок твой ужаствый код. Все обащения к VCL придется выкинуть и заменить их перемеными.


 
rolex   (2005-03-10 19:06) [33]

Тоесть второй вариант стоит осуществить?


> Все обащения к VCL придется выкинуть и заменить их перемеными.

Всмысле?


 
rolex   (2005-03-11 11:21) [34]

Ау!!! На вопросики то ответьте!!!


 
Anatoly Podgoretsky ©   (2005-03-11 12:06) [35]

Как опять?


 
Erik1 ©   (2005-03-11 12:23) [36]

Да что непонятного то? Например:
Form1.label14.Caption:=IntToStr(StrToInt(Form1.label14.Caption)+1);
Нахрен сносим и пишем Inc(Count); где Count: Integer;
Еще пример: Form2.ListBox1.Items[i] тоже убрать и заменить на TList в который заносим record. Надеюсь структуру record сам опишеш?!
ВСЕ ОБРЕЩЕНИЕ К VCL(Form, ListBox, пр..) ВЫКИНУТЬ!


 
rolex   (2005-03-11 18:55) [37]

А второй вариант стоит осуществить?


 
vertal ©   (2005-03-11 22:10) [38]

Запускай процедуру поиска и анализа имен файлов в отдельном потоке. В ней не должно быть никаких обращений к интерфейсу, и эта процедура должна быть полностью изолированной от остальной программы (связь только черз параметры). При нахождении нового подходящего файла кидай его имя в потокобезопасную очередь. Прикладные программы видимо должны считать, что FindFirst/FindNext - это предел скорости, так что с этой стороны оптимизация вряд ли возможна. Вместо MatchesMask создавай заранее необходимое число объектов TMask. Если выяснится, что узкое место - в операции проверке соответствия множеству масок, то можно попробовать сделать процедуру формирования конечного автомата, который будет проверять имя файла на соответсвие сразу любой из масок. В главном потоке по таймеру опустошай потокобезопасную очередь и выводи ее содержимое в контрол.
А код из [22] выглядит просто жутко:
Дикие имена переменых, отсутствие изоляции от остальной программы и от интерфейса, ProcessMessages понатыкано везде, лишние операции в цикле...
Это по-моему проще переписать.


 
rolex   (2005-03-12 20:14) [39]

Осуществил второй вариант (Сканирование в одном потоке, а обработка и интерфейс проги в другом потоке). В результате чего время сканирования увеличилось с 5мин. до 7мин. !!! =O


 
rolex   (2005-03-12 20:15) [40]

Осуществил второй вариант (Сканирование в одном потоке, а обработка и интерфейс проги в другом потоке). В результате чего время сканирования увеличилось с 5мин. до 7мин. !!! =0


 
Денч ©   (2005-03-12 21:07) [41]


> В результате чего время сканирования увеличилось с 5мин.
> до 7мин. !!! =0

Вот так да!!! Есть такая прога, sequoiaview называется (http://www.win.tue.nl/sequoiaview/), так у меня на сканирование диска объемом 13 Гб затратила около 20 секунд.
Может, попробовать asm поюзать?


 
rolex   (2005-03-13 10:47) [42]

Хм... на самом деле быстро!


 
Anatoly Podgoretsky ©   (2005-03-13 11:20) [43]

Есть такая хорошая программа Проводник называется.
157 гб просканировала за 3 минуты, 282000 файлов. Повторный запуск 7 секунд.
Это тем кто не верит, что два потока сильно затормозят сканирование, наглядно видно, что почти все время приходится на перемещение головок, при втором запуске головки уже не двигаются.


 
Дмитрий Мыльников   (2005-03-13 14:39) [44]

Да при чём тут вообще многопоточность, если базовый алгоритм написан криво, с постоянным обращением к визуальной части, которые вызывают весьма длительную перерисовку компонетов?
Тут хоть один поток, хоть два, хоть сто, толку всё равно не будет. И даже если делать повторный поиск, то сокращения времени с 3 мин до 7 сек как у проводника тоже не будет, поскольку основное время тратится вовсе не на поиск или даже перемещение головок, а на постоянную перерисовку визуальной части.

И вообще, у меня после прочтения нескольких тем, в которых так или иначе обсуждается многопоточность, сложилось впечатление, что создание множества потоков стало эдакой модной фишкой, да ещё и обросшей массой мифов. Типа, вот сделаю приложение многопоточным, и сразу будет мне счастье. А о том, что на большинстве компьютеров стоит ТОЛЬКО ОДИН ПРОЦЕССОР, почему-то никто не вспоминает. Ведь в случае с одним процессором, ЛЮБАЯ МНОГОПОТОЧНОСТЬ ЛИШЬ ИЛЛЮЗИЯ. И все приемущества, которые она даёт, сводятся к тому, что при грамотном использовании потоков прорамму можно сделать более простой и понятной, переложив решение части проблем на менеджер процессов ОС. Для срверных приложений, да ещё запускаемых на многопроцессорных системах, там да, разница будет существенной. Но и в этом случае нужно весьма немало времени потратить на проектирование программы.


 
Anatoly Podgoretsky ©   (2005-03-13 14:48) [45]

То что криво, так сразу сказали не в потоках счастье.


 
Palladin ©   (2005-03-13 15:02) [46]


> [44] Дмитрий Мыльников

Программа должна читать данные из COM порта и обрабатывать файлы. В COM порте данных нет. Программа ждет данные, но файлы не обрабатывает. Потому что поток один. Процессор один. Тут какой то дебил решил погнаться за "модной фишкой". Решил сделать два потока. Один будет заниматся чтением данных из COM порта, другой обрабатывать файлы. Блин, как хорошо получилось то. И файлы обрабатываются и программа не висит при отсутствии данных в COM. И тут он прочитал твой пост и прозрел. В срочном порядке вернул один поток. Ведь, как сказал Дмитрий Мыльников, все что он увидел при двух потоках оказалось иллюзией и неправдой...


 
Anatoly Podgoretsky ©   (2005-03-13 15:27) [47]

Palladin ©   (13.03.05 15:02) [46]
Так ты же не пытаешь читать один байт в одном потоке, а другой в другом. А остальное об вредности этого написали.
Механика однако. А у некоторых вера в чудо, вместо того, чтобы отшлифиовать алгоритм, верят в великую, тайную силу потоков.


 
Palladin ©   (2005-03-13 15:49) [48]


> [47] Anatoly Podgoretsky ©

Я не затрагиваю тему нескольких потоков читающих с диска. В приведенном примере два потока занимаются разными задачами. И объединение этих задач в одном потоке, работа достаточно сложная. Проще реализовать потоки. Учитывая, что могут появится и третья и четвертая задачи... Специально для Дмитрия Мыльникова.


 
Anatoly Podgoretsky ©   (2005-03-13 16:01) [49]

Но у него как раз первый случай.


 
Palladin ©   (2005-03-13 16:18) [50]

А мне показалось, он вообще идею нескольких потоков в программе попытался раскритиковать.


 
rolex   (2005-03-13 17:14) [51]

То есть мне первым делом следует переделать прямое обращение к компонентам во время сканирования?
Хорошо, но я не знаю как это сделать!
Ну к примеру: как можно заменить обращение к label"у который показывает число проанализированных файлов?
К примеру, в коде он выглядит так: Label1.caption:=IntToStr(schectchik); , где schetchik - integer, и есть то самое число проанализированных файлов.


 
Erik1 ©   (2005-03-14 11:17) [52]

Очень просто, надо один раз из 10-20 посылать PostMessage главной форме в параметрах(LParam) указать schectchik.


 
Anatoly Podgoretsky ©   (2005-03-14 11:20) [53]

Palladin ©   (13.03.05 16:18) [50]
Крестись, здесь простая вера в чудо. До чего только не дойдет русский программист, чтобы только не писать нормальную программу.

rolex   (13.03.05 17:14) [51]
Не надо пример с 282000 файлов, каждый проанализированный файл отражается в счетчике, время как я указал всего 7 секунд, из них на индикацию тратится малая доля.


 
Defunct ©   (2005-03-14 11:33) [54]

rolex   (13.03.05 17:14) [51]

Запустите на форме таймер, который раз в секунду будет обновлять информацию на Label"е и на всем остальном.


 
rolex   (2005-03-14 13:23) [55]


> Defunct ©   (14.03.05 11:33) [54]
> rolex   (13.03.05 17:14) [51]
>
> Запустите на форме таймер, который раз в секунду будет обновлять
> информацию на Label"е и на всем остальном.

Точно! Так и сделаю!
P.S. А таймер это впринципе он своим отдельным потоком и работает, так?


 
Digitman ©   (2005-03-14 13:40) [56]


> P.S. А таймер это впринципе он своим отдельным потоком и
> работает, так?


нет, не так.

за обработку его событий таймера отвечает поток, который создал этот таймер


 
rolex   (2005-03-14 14:56) [57]


> Defunct ©   (14.03.05 11:33) [54]
> rolex   (13.03.05 17:14) [51]
>
> Запустите на форме таймер, который раз в секунду будет обновлять
> информацию на Label"е и на всем остальном.

Так поможет этот способ тогда или нет?


 
Defunct ©   (2005-03-14 15:25) [58]

rolex   (14.03.05 14:56) [57]

Определенно. Ускорит работу программы причем на много (в разы).
Поток поиска пусть занимается только поиском, никаких сообщений главной форме, никаких synchronize, и никаких обращений к VCL, кроме сигнализации о завершении поиска.

Напишу небольшой пример позже.
Выложу здесь.


 
rolex   (2005-03-14 16:08) [59]


> Defunct ©   (14.03.05 15:25) [58]
> rolex   (14.03.05 14:56) [57]
>
> Определенно. Ускорит работу программы причем на много (в
> разы).
> Поток поиска пусть занимается только поиском, никаких сообщений
> главной форме, никаких synchronize, и никаких обращений
> к VCL, кроме сигнализации о завершении поиска.
>
> Напишу небольшой пример позже.
> Выложу здесь.

Ну спасибо!


 
Defunct ©   (2005-03-14 17:06) [60]

Обещанный пример.

unit Unit1;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs, StdCtrls, Masks, ComCtrls, Grids;

const
  WM_UPDATELIST   =   WM_USER + 90;

type
  TSearchThread = class(TThread)
  private
     List            : TStrings;
     fDailyList      : TStrings;
     fOwnerHandle    : HWND;
     fDir            : String;
     Mask            : String;
     fCount          : Integer;
     fWhenToSendList : TDateTime;

     function  GetDailyData:TStrings;
     procedure TryToUploadTheList(Forced: boolean);
  protected
     procedure Execute;override;
  public
     property ExportList: TStrings read GetDailyData;
     property Count:Integer read fCount;

     constructor Create(AOwner: Hwnd;  Dir,  AMask:  string);
  end;

 TForm2 = class(TForm)
   Button1: TButton;
   StatusBar1: TStatusBar;
   ScrollBar1: TScrollBar;
   StringGrid1: TStringGrid;
   procedure Button1Click(Sender: TObject);
   procedure ScrollBar1Change(Sender: TObject);
 private
   fTime    : TDateTime;
 public
   ST       : TSearchThread;
   Strings  : TStrings;

   procedure UpdateList(var Msg:TMessage);message WM_UPDATELIST;
   procedure UpdateControls;
   procedure RedrawGrid;
   procedure RegisterFinishOfSearching( Sender : TObject );
 end;

var
 Form2: TForm2;

implementation

{$R *.dfm}

{***********************************}
{*********** &#239;&#238;&#242;&#238;&#234; &#239;&#238;&#232;&#241;&#234;&#224; **********}
{***********************************}
constructor TSearchThread.Create;
begin
  inherited Create(True);

  if Dir <> "" then
     fDir := Dir
  else
     fDir := "c:\";

  if AMask <> "" then
     Mask := AMask
  else
     Mask := "*.*";

  fDailyList := nil;
  fOwnerHandle := AOwner;
  fCount := 0;
  fWhenToSendList := 0;
  Priority := tpIdle;
  FreeOnTerminate := True;
  Resume;
end;

procedure TSearchThread.Execute;

{ немного приспособленная для нашего примера
 процедура ScanDir (C) Юрий Зотов }
    procedure  ScanDir(Dir:  string);
    var
        SR:  TSearchRec;
    begin
        Dir  :=  IncludeTrailingBackSlash(Dir);
        if  FindFirst(Dir  +  "*.*",  faAnyFile  -  faVolumeID,  SR)  =  0  then
        try
            repeat
                if  (SR.Name  <>  ".")  and  (SR.Name  <>  "..")  then
                    if  SR.Attr  and  faDirectory  <>  0  then
                        ScanDir(Dir  +  SR.Name)
                    else
                        if  MatchesMask(SR.Name,  Mask)  then
                            begin
                               List.Add(Dir  +  SR.Name);
                               inc(fCount);                // <- добавлено для примера
                               TryToUploadTheList(False);  // <- добавлено для примера
                            end
            until  FindNext(SR)  <>  0
        finally
            FindClose(SR)
        end
  end;

begin
  try
     List := TStringList.Create;
     ScanDir( fDir );
     TryToUploadTheList( True );
  except
     ShowMessage("Alles at Execute");
  end;
end;

function TSearchThread.GetDailyData;
begin
 Result := fDailyList;
 fDailyList := nil;
end;

procedure TSearchThread.TryToUploadTheList;
begin
 if Forced then
    begin
       if Assigned( fDailyList ) then
          fDailyList.Free;
       fDailyList := List;
       PostMessage( fOwnerHandle, WM_UPDATELIST, 0,0);
       Exit
    end;

 if fWhenToSendList > 0 then
    try
       if GetTime >= fWhenToSendList then
          if fOwnerHandle <> 0  then
          begin
             if Assigned( fDailyList ) then
                fDailyList.Free;
             fDailyList := List;
             List := TStringList.Create;
             fWhenToSendList := GetTime + (0.2 / (3600*24) );
             PostMessage( fOwnerHandle, WM_UPDATELIST, 0,0)
          end
    except
       on E:Exception do ShowMessage("Alles at TryToUpload")
    end
 else // инициализация таймера
    fWhenToSendList := GetTime + (0.2 / (3600*24) );
end;

{***********************************}

procedure TForm2.Button1Click(Sender: TObject);
begin
  fTime := Now;
  Strings := TStringList.Create;
  if not Assigned(ST) then
     ST := TSearchThread.Create( Handle, "c:\", "*.*");
  ST.OnTerminate := RegisterFinishOfSearching;
end;

procedure TForm2.RegisterFinishOfSearching;
begin
 fTime := Now - fTime;
 ShowMessage("Total time: "+FormatDateTime("hh:nn:ss:zzz", fTime));
 ST := nil
end;

procedure TForm2.RedrawGrid;
var
  i        : integer;
  EndPos   : integer;
begin
  EndPos := ScrollBar1.Position + StringGrid1.RowCount;

  if EndPos >= Strings.Count then
     EndPos := Strings.Count - 1;

  for i := ScrollBar1.Position to EndPos do
      StringGrid1.Cells[0, i - ScrollBar1.Position] := Strings[i];
end;

procedure TForm2.UpdateControls;
begin
  ScrollBar1.Min := 0;
  ScrollBar1.Max := ST.Count - StringGrid1.RowCount;
  StatusBar1.Panels[0].Text := "Files found: "+IntToStr( ST.Count );

  RedrawGrid;
end;

procedure TForm2.UpdateList;
var
 AList : TStrings;
begin
  try
     AList := ST.ExportList;
     Strings.AddStrings( AList );
     AList.Free;
     UpdateControls;
  except
     on E:Exception do ShowMessage(E.ClassName+" " +E.Message)
  end
  inherited;
end;

procedure TForm2.ScrollBar1Change(Sender: TObject);
begin
  RedrawGrid;
end;

end.


 
Defunct ©   (2005-03-14 17:07) [61]

Unit1.DFM

object Form2: TForm2
 Left = 332
 Top = 265
 Width = 504
 Height = 393
 Caption = "Form2"
 Color = clBtnFace
 Font.Charset = DEFAULT_CHARSET
 Font.Color = clWindowText
 Font.Height = -11
 Font.Name = "MS Sans Serif"
 Font.Style = []
 OldCreateOrder = False
 PixelsPerInch = 96
 TextHeight = 13
 object Button1: TButton
   Left = 408
   Top = 8
   Width = 75
   Height = 25
   Caption = "Run"
   TabOrder = 0
   OnClick = Button1Click
 end
 object StatusBar1: TStatusBar
   Left = 0
   Top = 347
   Width = 496
   Height = 19
   Panels = <
     item
       Width = 50
     end>
 end
 object ScrollBar1: TScrollBar
   Left = 344
   Top = 0
   Width = 16
   Height = 345
   Kind = sbVertical
   PageSize = 0
   TabOrder = 2
   OnChange = ScrollBar1Change
 end
 object StringGrid1: TStringGrid
   Left = 0
   Top = 0
   Width = 345
   Height = 347
   Align = alLeft
   ColCount = 1
   DefaultColWidth = 340
   DefaultRowHeight = 18
   FixedCols = 0
   RowCount = 18
   FixedRows = 0
   Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goRowSelect]
   ScrollBars = ssNone
   TabOrder = 3
 end
end


 
Defunct ©   (2005-03-14 17:13) [62]

[60]
50 тыс файлов за 1.7 секунды (повторный поиск), почти как в проводнике ;>


 
begin...end ©   (2005-03-14 17:25) [63]

> Defunct ©   (14.03.05 17:06) [60]

> inherited Create(True);
> ...
> Resume;

Это можно выкинуть.

P.S. А почему List нигде не освобождается? Или я что-то не заметил?


 
Alexander Panov ©   (2005-03-14 17:26) [64]

begin...end ©   (14.03.05 17:25) [63]
Это можно выкинуть.


С какой стати?


 
begin...end ©   (2005-03-14 17:28) [65]

> Alexander Panov ©   (14.03.05 17:26) [64]

А для чего это нужно?


 
Alexander Panov ©   (2005-03-14 17:32) [66]

begin...end ©   (14.03.05 17:28) [65]
А для чего это нужно?


Для установки переменных, конечно.
Причем, если исходить из конкретной платформы(D7), то это(в принципе) не обязательно.
Но исходя из общей логики, и учитывая, что код будет работать в D5(например), то этот дополнительный код необходим для универсальности.


 
Alexander Panov ©   (2005-03-14 17:33) [67]

И еще, как насчет изменения логики TThread в следующих версиях?


 
begin...end ©   (2005-03-14 17:34) [68]

Ну вопрос-то был про Delphi 7.


 
Defunct ©   (2005-03-14 17:35) [69]

> P.S. А почему List нигде не освобождается? Или я что-то не заметил?

TForm2.UpdateList


 
GuAV ©   (2005-03-14 17:36) [70]


> Alexander Panov ©


Так что, если заменить на inherited Create(False); ,  универсальности не будет ?


 
Alexander Panov ©   (2005-03-14 17:44) [71]

GuAV ©   (14.03.05 17:36) [70]
Так что, если заменить на inherited Create(False); ,  универсальности не будет ?


Не будет.

Код будет направильно работать в D5, например,
так как, начиная с D6 изменилась реализация TObject - появился метод AfterConstruction, который вызывается после завершения выполнения любого конструктора.


 
Defunct ©   (2005-03-14 17:47) [72]

GuAV ©   (14.03.05 17:36) [70]

constructor TThread.Create(CreateSuspended: Boolean);
var
 Flags: DWORD;
begin
 inherited Create;
 AddThread;
 FSuspended := CreateSuspended;
 Flags := 0;
 if CreateSuspended then Flags := CREATE_SUSPENDED;
 FHandle := BeginThread(nil, 0, @ThreadProc, Pointer(Self), Flags, FThreadID);
end;


 
begin...end ©   (2005-03-14 17:50) [73]

> Defunct ©   (14.03.05 17:47) [72]

Delphi 5?


 
Defunct ©   (2005-03-14 17:51) [74]

[73]

угу


 
GuAV ©   (2005-03-14 18:04) [75]


> так как, начиная с D6 изменилась реализация TObject -
> появился метод AfterConstruction


Аж только в D6 ? не знал...


 
Alexander Panov ©   (2005-03-14 18:09) [76]

GuAV ©   (14.03.05 18:04) [75]

Насчет реализации AfterConstruction в D6 может быть заблуждаюсь, так как обратил внимание на него только лишь в связи с изменением реализации TThread в D6.


 
begin...end ©   (2005-03-14 18:11) [77]

> GuAV ©   (14.03.05 18:04) [75]
> Alexander Panov ©   (14.03.05 18:09) [76]

AfterConstruction в Delphi 4 появился.


 
Alexander Panov ©   (2005-03-14 18:26) [78]

begin...end ©   (14.03.05 18:11) [77]

Ок, спасибо, буду знать.

К сожалению, только реализация TThread отстала по времени.


 
rolex   (2005-03-14 18:32) [79]

Всё ништяк прога! Всю ночь буду в код въезжать, чтобы сибе также сделать!!! Скорость рулевая!!!
Тока вот тут ошибочка:
procedure TForm2.UpdateList;
var
AList : TStrings;
begin
 try
    AList := ST.ExportList;
    Strings.AddStrings( AList );
    AList.Free;
    UpdateControls;
 except
    on E:Exception do ShowMessage(E.ClassName+" " +E.Message)
 end
 inherited;
end;

То что жирным выделил удалил из кода. А то компилятор ругался.

А dpr файл такой должен получиться, да?:
program Project1;

uses
 Forms,
 Unit1 in "Unit1.pas" {Form1};

{$R *.res}

begin
 Application.Initialize;
 Application.CreateForm(TForm2, Form2);
 Application.Run;
end.


 
rolex   (2005-03-14 21:57) [80]

To Defunct:
Ууу... я страшный баг нашёл.
Когда запустите прогу, посмотрите в Диспетчере Задач скока она места в ОЗУ съедает. Ок запомнили. Потом каждый раз при нажатии кнопки "Скан", размер проги в ОЗУ всё больше и больше растёт!!!


 
Дмитрий Мыльников   (2005-03-14 22:55) [81]

Небольшое замечание по ООП в Delphi.

Во-первых, между записью

Inherited;

и

Inherited Create(False);

очень большая разница. Не помню начиная с какй версии, но в D7 точно, если написано просто Inherited, то компилятор подставляет вызов функции предка только в тех случаях, когда она в нём действительно существует. То есть, если в предке она объявлена abstract, либо не объявлено вовсе, то никакого вызова вставлено не будет. Зато если позже она перестанет быть абстрактной или появляется в предке, и в ней появится какой-то код, то вызов будет выполнен.
Если же написать с явным указанием, как во втором случае, то компилятор будет пытаться подставлять вызов всегда, в результате чего будет либо ошибка во время компиляции, либо abstract error во время выполнения (жаль только, что этот механизм не работает для функций).


 
Anatoly Podgoretsky ©   (2005-03-14 22:59) [82]

Естественно это только для методов.


 
Дмитрий Мыльников   (2005-03-14 23:06) [83]

А я бы вообще запретил использовать статические процедуры и функции. :)))
Просто недавно пришлось одну прогу переделывать, так мы там с этими статическими функциями намучались. Вроде начнается иерархия классов, всё как у взрослых, только большая часть фукнций в базовых классах объявлена abstract. А ещё чуть позже выяснилось, что в конечных классах понатыкано вызовов из статических функций, и всё это ООП тем самым "коту под хвост". Её уже не перекроешь никак, и виртуальной не объявишь. Короче, пришлось всё почти полностью переделывать...


 
Anatoly Podgoretsky ©   (2005-03-14 23:09) [84]

Ну это уровень компетентности программиста.
Молодец, наш человек - переписать все нафиг :-)


 
GuAV ©   (2005-03-14 23:13) [85]

А самое  прикольное то, что этот inherited хоть и нафиг не нужен для WM_USER + 90, ошибка компиляции вызванная его наличием IMHO указывает на ошибку при копировании кода, т.к. в message методе inherited есть вызов обработчика сообщения наследника, и не исключено что в этом и заключается причина [80].


 
Defunct ©   (2005-03-15 10:10) [86]

except
   on E:Exception do ShowMessage(E.ClassName+" " +E.Message)
end
inherited;
end;
То что жирным выделил удалил из кода. А то компилятор ругался.


точка с запятой после end потерялась.

rolex   (14.03.05 21:57) [80]

Strings := TStringList.Create;
В OnCreate формы перенесите

А в Button1Click - замените Strings := TStringList.Create; на Strings.Clear;



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

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

Наверх





Память: 0.74 MB
Время: 0.038 c
4-1108371154
Интересующийся
2005-02-14 11:52
2005.03.27
OnKeyDown


14-1109930477
Тульский
2005-03-04 13:01
2005.03.27
Кванторы


1-1110788781
denis24
2005-03-14 11:26
2005.03.27
Работа со списком указателей


1-1110734849
Sour
2005-03-13 20:27
2005.03.27
Как определить в каком режиме открыта форма (модальном или нет)


3-1109074234
andrey__
2005-02-22 15:10
2005.03.27
ComboBox со значениями из поля





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский