пишу прогу, суть ее в том, что она делает поиск файлов с определенным расширением. когда находит, то открывает его и если там есть слово "new" закрывает и запускает поток на обработку данного файла. Имя файла передается потоку через переменую в public, главной формы. поток плучив имя файла открывает его выполняет некие операции и записывает туда "done". на этом обработка завершена. проблема в том, что посе выполнения программы в некоторых файлах "done" вообще отсутствует, а в некоторых не один, а целых два. Помогите решить это проблему, очень нужно..
Уважаемые авторы вопросов! Большая просьба сообщить о результатах решения проблемы на этой странице. Иначе, следящие за обсуждением, возможно имеющие аналогичные проблемы, не получают ясного представления об их решении. А авторы ответов не получают обратной связи. Что можно расценивать, как проявление неуважения к отвечающим от автора вопроса.
10-01-2008 11:27
Мы с Вами пили на брутершафт? Хм, не помню такого...:(
>>>Так что именно ты читал?
Вы хотите, чтобы я перечислил Вам все, что читал за последние 8-10 лет? Помилуйте, где же я упомню:(
Ну по Windows могу порекомендовать Рихтера - все, что найдете, кроме той, где он пишет про NET, эту я и сам не читал:)
Вот как тут быть?:( Промолчать - не вежливо, сказать правду - Вы обидитесь:(
Ответ-то прост - кроме прочего, выбирая оптимальное количество потоков. Но это только сказать просто, а вот реализовать - задача нетривиальная. И браться за нее стоит тогда, когда, во-первых, вопросы, подобные заданному Вами просто не возникают, а во-вторых, когда это реально нужно, когда овчинка стоит выделки. И прежде надо хорошенько разобраться с многопоточностью, нутром ее прочувствовать, так сказать.
Ладно, хоть рановато Вам это, но все-же простой пример на основе Вашего вопроса покажу, однако дальше Вам придется осваиваться самостоятельно, читая хелпы, экспирементируя и думая.
procedure TForm1.FormCreate(Sender: TObject);
var
n: integer;
begin
for n:= 0 to Pred(ProcessorsCount * ThreadPerProcessor) do
TMyThread.Create;
end;
procedure TForm1.FormDestroy(Sender: TObject);
var
n: integer;
begin
for n:= 0 to Pred(ProcessorsCount * ThreadPerProcessor) do
CPort.SetCompletion(0, 0, TOverlappedEx(nil^));
end;
procedure TForm1.Button1Click(Sender: TObject);
var
SR: TSearchRec;
F: TextFile;
s: string;
PTask: PTaskRec;
POvp: POverlappedEx absolute PTask;
begin
if FindFirst('D:\Temp\Test\*.txt', faAnyFile, SR) = 0 then
repeat
AssignFile(F, 'D:\Temp\Test\'+SR.Name);
Reset(F);
Read(f, s);
CloseFile(F);
if s = 'new' then
begin
New(PTask);
PTask.FileName:= SR.Name;
CPort.SetCompletion(0, 1, POvp^);
end;
until FindNext(SR) <>0;
end;
procedure TForm1.Button2Click(Sender: TObject);
var
s: string;
n: integer;
begin
s:= 'new'#13#10 + StringOfChar('x', 1024) + #13#10;
for n:= 0 to 511 do
begin
with TFileStream.Create('D:\Temp\Test\' + IntToStr(n) + '.txt', fmCreate) do
try
Size:= 0;
WriteBuffer(s[1], Length(s));
finally
free;
end;
end;
end;
{ TMyThread }
constructor TMyThread.Create;
begin
FreeOnTerminate:= true;
inherited Create(false);
end;
procedure TMyThread.Execute;
var
Bytes, Key: Cardinal;
pOvp: POverlappedEx;
pTask: PTaskRec absolute pOvp;
s: string;
F: TextFile;
begin
while CPort.WaitCompletion(Bytes, Key, pOvp) do
begin
if Key = 0 then Break;
if pTask <> nil then
begin
s:= pTask.FileName;
Dispose(pTask);
end else
Continue;
Так я и сейчас не понимаю, что Вы имели в виду в посте [08-01-2008 16:00], ведь пост [08-01-2008 11:58] к тому времени уже был:)
>>>только межет объясните почему вы считаете вызов потока бесполезным?
Да нет, я не считаю создание доп. потоков бесполезным в Вашем случае, я считаю неправильным то, как это делаете Вы. Я ведь что написал:
При большом количестве файлов Ваш код будет работать заметно дольше, чем в однопоточном варианте[/Quote
Ведь смотрите, Вы на каждый найденный файл создаете по потоку. Представьте, что файлов хотя-бы сто. Ну ни разу не поверю, что эта программа будет выполняться на машине с сотней процессоров. Следовательно ОС вынуждена будет перключаться с одного потока на другой, отдавая процессор то одному потоку, то другому. А такое переключение не очень-то быстрая операция. Ну на NT еще куда ни шло, на 9х вообще было швах:(
Но время, затрачиваемое на переключение потоков - это только одна сторона. Чтобы стало понятней, давайте рассмотрим сильно упрощенный сценарий.
Итак, имеем один процессор и 10 файлов. Пусть на обработку одного файла уходит 10 секунд, а квант планировщика равен одной секунде. Вариант 1 - один поток
Очевидно, чтто через 10 секунд будет обработан 1-й файл, через 20 - 2-й и т.д. На все файлы уйдет 10х10=100 секунд. Вариант 2 - по потоку на каждый файл
1-й поток начнет обрабатывать файл и за одну секунду выполнит 10% работы. После этого процессор будет отдан 2-му потоку. Тот сделает свои 10% над вторым файлом и процессор будет отдан 3-му потоку, и т.д. Через 10 секунд будут по очереди запущены на 1 сек. все 10 потоков и очередь опять дойдет до первого. Таким образом, у каждого потока на 10% работы уходит 10 секунд. Если продолжить дальше, то нетрудно убедиться, что через 90 секунд будет обработано 90% каждого из файлов, через 91сек - 100% первого, через 92 - 100% 2-го, через 100 секунд обработка всех файлов будет завершена.
Как видите, чистого времени в обоих случаях на 10 файлов уходит одинаково, и это без учета времени на переключение потоков, а оно в многопоточном варианте было выполнено 100 раз.
Вот и получается, что никакого ускорения работы от многопоточности мы не получили, а совсем даже наоборот.
А Вы еще написали
>>>эти некоторые операции выполняются с помощю компонент расположеных на главной форме
что само по себе предполагает какую-никакую синхронизацию с ее накладными расходами.
Да приплюсуйте к этому затраты системы на создание и уничтожение потоков, свои расходы на создание-уничтожение объектов-потомков TThread - вот и получается, что от слишком большого числа потоков одни убытки.
По моим наблюдениям, при работе с жестким диском оптимальное количество потоков где-то от двух до пяти на процессор. Но это если используется пул потоков, управляемый IO Completion Port. А без такого пула делать более двух потоков на процессор смысла нет.
Ну вот видите, все отлично работает, а говорите, что не понимаете о чем речь! ВСЕМ БОЛЬШОЕ СПАСИБО! Все работает. только межет объясните почему вы считаете вызов потока бесполезным?
И чем же, посзвольте полюбопытствовать, Ваша "помощь" отличается от моей из поста [08-01-2008 11:58]. Ну кроме отсутствия (у Вас) вызова FreeOnTerminate. Вы, как и автор, считаете, что мусор за Вами должна убирать уборщица тетя Клава?
procedure MyThread.Execute;
var
F: TextFile;
begin
AssignFile(F, 'C:\testThread\docs\'+FN);
Append(F);
WriteLn(F, 'done');
CloseFile(F);
end;
end.
вот вызов, правда не совсем понятно зачем это нужно
procedure TForm1.Button1Click(Sender: TObject);
var
SR: TSearchRec;
F: TextFile;
s: string;
begin
if FindFirst('C:\testThread\docs\*.txt', faAnyFile, SR) = 0 then begin
AssignFile(F, 'C:\testThread\docs\'+SR.Name);
Reset(F);
Read(f, s);
CloseFile(F);
repeat
if s = 'new' then begin
MyThread.Create(SR.Name);
end;
дело в том что эти некоторые операции выполняются с помощю компонент расположеных на главной форме. с помощю этого компонента поток отправляет информацию из докумена на сервак и получив "ок" пишет "done". Так что быстрей это сделать через потоки, а не в главном коде!
Вы полагаете?:)) Ну быстрей, так быстрей. Бог в помощь, как говорится.
открывает его выполняет некие операции
дело в том что эти некоторые операции выполняются с помощю компонент расположеных на главной форме. с помощю этого компонента поток отправляет информацию из докумена на сервак и получив "ок" пишет "done". Так что быстрей это сделать через потоки, а не в главном коде!
Первым делом - переменную Str изничтожить как врага прогрессивного человечества. Имя файла передавать параметром в конструкторе MyThread и сохранять во внутреннем поле.
Кроме того, не худо бы объекты MyThread не только создавать, но и уничтожать.
Кроме слова "new" полезно искать и слово "done" - чтобы исключить повторную обработку. Либо где-то хранить список обработанных и сверяться с ним при обнаружении очередного файла с "new" внутри.[/
А основной поок и так отправляет на обработку только не обработанные файлы!
Кроме слова "new" полезно искать и слово "done" - чтобы исключить повторную обработку. Либо где-то хранить список обработанных и сверяться с ним при обнаружении очередного файла с "new" внутри.
А мне вот интересно, как Вы себе представляете эту самую помощь при ТАКОЙ формулировке вопроса? "У меня под кроватью какой-то подземный стук. Объясните, что это такое."
Можно конечно посоветовать - синхронизируйте работу с файлами, но судя по формулировке вопроса, совет этот будет совершенно бесполезным:((
когда находит, то открывает его и если там есть слово "new" закрывает и запускает поток на обработку данного файла
Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter. Функция может не работать в некоторых версиях броузеров.