Rambler's Top100
"Knowledge itself is power"
F.Bacon
Поиск | Карта сайта | Помощь | О проекте | ТТХ  
 Круглый стол
  
Правила КС
>> Настройки

Фильтр вопросов
>> Новые вопросы
отслеживать по
>> Новые ответы

Избранное

Страница вопросов
Поиск по КС


Специальные проекты:
>> К л ю к в а
>> Г о л о в о л о м к и

Вопрос №

Задать вопрос
Off-topic вопросы

Помощь

 
 К н и г и
 
Книжная полка
 
 
Библиотека
 
  
  
 


Поиск
 
Поиск по КС
Поиск в статьях
Яndex© + Google©
Поиск книг

 
  
Тематический каталог
Все манускрипты

 
  
Карта VCL
ОШИБКИ
Сообщения системы

 
Форумы
 
Круглый стол
Новые вопросы

 
  
Базарная площадь
Городская площадь

 
   
С Л С

 
Летопись
 
Королевские Хроники
Рыцарский Зал
Глас народа!

 
  
ТТХ
Конкурсы
Королевская клюква

 
Разделы
 
Hello, World!
Лицей

Квинтана

 
  
Сокровищница
Подземелье Магов
Подводные камни
Свитки

 
  
Школа ОБЕРОНА

 
  
Арсенальная башня
Фолианты
Полигон

 
  
Книга Песка
Дальние земли

 
  
АРХИВЫ

 
 

Сейчас на сайте присутствуют:
 
  
 
Во Флориде и в Королевстве сейчас  02:55[Войти] | [Зарегистрироваться]
Ответ на вопрос № 58287

08-01-2008 08:34
пишу прогу, суть ее в том, что она делает поиск файлов с определенным расширением. когда находит, то открывает его и если там есть слово "new" закрывает и запускает поток на обработку данного файла. Имя файла передается потоку через переменую в public, главной формы. поток плучив имя файла открывает его выполняет некие операции и записывает туда "done". на этом обработка завершена. проблема в том, что посе выполнения программы в некоторых файлах "done" вообще отсутствует, а в некоторых не один, а целых два. Помогите решить это проблему, очень нужно..

[+] Добавить в избранные вопросы

Отслеживать ответы на этот вопрос по RSS

Ответы:


Уважаемые авторы вопросов! Большая просьба сообщить о результатах решения проблемы на этой странице.
Иначе, следящие за обсуждением, возможно имеющие аналогичные проблемы, не получают ясного представления об их решении. А авторы ответов не получают обратной связи. Что можно расценивать, как проявление неуважения к отвечающим от автора вопроса.

10-01-2008 11:27
Мы с Вами пили на брутершафт? Хм, не помню такого...:(

>>>Так что именно ты читал?

Вы хотите, чтобы я перечислил Вам все, что читал за последние 8-10 лет? Помилуйте, где же я упомню:(
Ну по Windows могу порекомендовать Рихтера - все, что найдете, кроме той, где он пишет про NET, эту я и сам не читал:)
 NS

10-01-2008 10:37 | Сообщение от автора вопроса
Так что именно ты читал?

09-01-2008 21:39
>>>а вот откуды вы все это знаете

Три варианта:

  • Я родился с этим знанием
  • Ко мне во сне Билл Гейтс приходил и все-все рассказал
  • Читал документацию, книжки, форумы разные... Думал, пробовал и опять думал


Выбирайте по вкусу.
 NS

09-01-2008 13:52 | Сообщение от автора вопроса
а вот откуды вы все это знаете? направте меня путь истенный..

09-01-2008 13:06
Вот как тут быть?:( Промолчать - не вежливо, сказать правду - Вы обидитесь:(

Ответ-то прост - кроме прочего, выбирая оптимальное количество потоков. Но это только сказать просто, а вот реализовать - задача нетривиальная. И браться за нее стоит тогда, когда, во-первых, вопросы, подобные заданному Вами просто не возникают, а во-вторых, когда это реально нужно, когда овчинка стоит выделки. И прежде надо хорошенько разобраться с многопоточностью, нутром ее прочувствовать, так сказать.

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


unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, CompletionPort, StdCtrls;

type
  TTaskRec = record
    FileName: string;
  end;
  PTaskRec = ^TTaskRec;

  TMyThread = class(TThread)
  protected
    procedure Execute; override;
  public
    constructor Create();
  end;

  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  CPort: TCompletionPort;
  ProcessorsCount: integer;
const
  ThreadPerProcessor = 4;

implementation

{$R *.dfm}

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;

    AssignFile(F, 'D:\Temp\Test\' + s);
    Append(F);
    WriteLn(F, 'done');
    CloseFile(F);
  end;
end;

procedure Init;
var
  SysInfo: TSystemInfo;
begin
  CPort:= TCompletionPort.Create();
  GetSystemInfo(SysInfo);
  ProcessorsCount:= integer(SysInfo.dwNumberOfProcessors);
end;

initialization
  Init;
finalization
  CPort.Free;
end.


Поэксперементируйте с константой ThreadPerProcessor.

Да, модуль CompletionPort можно взять здесь »вопрос КС №56098«
 NS

09-01-2008 12:22 | Сообщение от автора вопроса
NS, тогда как вы предпологате ускорить процесс?

09-01-2008 11:22
Ах ты, не закрыл тэг:(( Ну да ладно, вроде и так нормально читается.
 NS

09-01-2008 11:21
>>> а говорите, что не понимаете о чем речь!

Так я и сейчас не понимаю, что Вы имели в виду в посте [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. А без такого пула делать более двух потоков на процессор смысла нет.
 NS

09-01-2008 10:07 | Сообщение от автора вопроса
Ну вот видите, все отлично работает, а говорите, что не понимаете о чем речь! ВСЕМ БОЛЬШОЕ СПАСИБО! Все работает. только межет объясните почему вы считаете вызов потока бесполезным?

09-01-2008 01:31
2 Kealon

И чем же, посзвольте полюбопытствовать, Ваша "помощь" отличается от моей из поста [08-01-2008 11:58]. Ну кроме отсутствия (у Вас) вызова FreeOnTerminate. Вы, как и автор, считаете, что мусор за Вами должна убирать уборщица тетя Клава?
 NS

09-01-2008 01:21 | Комментарий к предыдущим ответам
Господа, кто-нибудь понимает, чего он хочет?
Чтобы помогли избавиться от "стука под кроватью" ;-) :-D

09-01-2008 01:18
код потока, как вам советовали его переписать:


unit Unit1;

interface

uses
  Classes;

type
  MyThread = class(TThread)
  private
    fn:string;
    { Private declarations }
  protected
    procedure Execute; override;
  public
    constructor Create(const AFN:string);
  end;

implementation

uses MainUnit;
constructor MyThread.Create(const AFN:string);
begin
  inherited Create(true);
  FN:=AFN;
  Resume; 
end;

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;

  until FindNext(SR) <>0;
end;
end;

end.




08-01-2008 21:07
Нет, мне это нравится:)

2 cibermind

Так какая Вам помощь-то нужна, Вы можете наконец сформулировать? В какой форме? Вы сделали то, что Вам уже было сказано?

2 ALL

Господа, кто-нибудь понимает, чего он хочет?
 NS

08-01-2008 16:00 | Сообщение от автора вопроса
помимо господней помощи, есть кто-нибудь кто могбы помочь?

08-01-2008 12:49
дело в том что эти некоторые операции выполняются с помощю компонент расположеных на главной форме. с помощю этого компонента поток отправляет информацию из докумена на сервак и получив "ок" пишет "done". Так что быстрей это сделать через потоки, а не в главном коде!

Вы полагаете?:)) Ну быстрей, так быстрей. Бог в помощь, как говорится.
 NS

08-01-2008 12:02 | Сообщение от автора вопроса
открывает его выполняет некие операции 
дело в том что эти некоторые операции выполняются с помощю компонент расположеных на главной форме. с помощю этого компонента поток отправляет информацию из докумена на сервак и получив "ок" пишет "done". Так что быстрей это сделать через потоки, а не в главном коде!

08-01-2008 11:58
>>>ну дык научите же как это делать..

В смысле? Передавать параметр в процедуру?


type
  MyThread = class(TThread)
  private
    { Private declarations }
    FFileName: string;
  protected
    procedure Execute; override;
  public
    constructor Create(const FileName: string);
  end;

constructor MyThread.Create;
begin
  FFileName:= FileName;
  FreeOnTerminate:= true;
  inherited Create(false);
end;

procedure MyThread.Execute;
var
F: TextFile;
begin
AssignFile(F, 'C:\testThread\docs\'+FFileName);
Append(F);
WriteLn(F, 'done');
CloseFile(F);
end;

 NS

08-01-2008 11:52
И по поводу "Done" - провярять его отсутствие в файле все-таки видимо надо. Либо складывать обработанные файлы в отдельную папку.

ЗЫ При большом количестве файлов Ваш код будет работать заметно дольше, чем в однопоточном варианте.
 NS

08-01-2008 11:47 | Сообщение от автора вопроса
ПОЖАЛУЙСТА

08-01-2008 11:47 | Сообщение от автора вопроса
ну дык научите же как это делать..

08-01-2008 11:45
Первым делом - переменную Str изничтожить как врага прогрессивного человечества. Имя файла передавать параметром в конструкторе MyThread и сохранять во внутреннем поле.
Кроме того, не худо бы объекты MyThread не только создавать, но и уничтожать.
 NS

08-01-2008 11:26 | Сообщение от автора вопроса
Привожу код главной формы:


unit MainUnit;

interface

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

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  STR: String;

implementation

uses Unit1;

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
SR: TSearchRec;
F: TextFile;
s: string;
begin
if FindFirst('C:\testThread\docs\*.txt', faAnyFile, SR) = 0 then
begin
  repeat
  AssignFile(F, 'C:\testThread\docs\'+SR.Name);
  Reset(F);
  Read(f, s);
  CloseFile(F);

  if s = 'new' then
  begin
    STR := SR.Name;
    MyThread.Create(False);
  end;

  until FindNext(SR) <>0;
end;
end;

end.



код потока:


unit Unit1;

interface

uses
  Classes;

type
  MyThread = class(TThread)
  private
    { Private declarations }
  protected
    procedure Execute; override;
  end;

implementation

uses MainUnit;

procedure MyThread.Execute;
var
F: TextFile;
begin
AssignFile(F, 'C:\testThread\docs\'+STR);
Append(F);
WriteLn(F, 'done');
CloseFile(F);
end;
end.


08-01-2008 11:25
Кроме слова "new" полезно искать и слово "done" - чтобы исключить повторную обработку. Либо где-то хранить список обработанных и сверяться с ним при обнаружении очередного файла с "new" внутри.[/

А основной поок и так отправляет на обработку только не обработанные файлы!

08-01-2008 11:22 | Сообщение от автора вопроса
потомучто обработка файла занимает больше времени, за тоже время закончится сканирование файлов в папке основным потоком.

08-01-2008 11:19
Кроме слова "new" полезно искать и слово "done" - чтобы исключить повторную обработку. Либо где-то хранить список обработанных и сверяться с ним при обнаружении очередного файла с "new" внутри.

08-01-2008 09:40
>>>Помогите решить это проблему, очень нужно..

А мне вот интересно, как Вы себе представляете эту самую помощь при ТАКОЙ формулировке вопроса? "У меня под кроватью какой-то подземный стук. Объясните, что это такое."

Можно конечно посоветовать - синхронизируйте работу с файлами, но судя по формулировке вопроса, совет этот будет совершенно бесполезным:((

когда находит, то открывает его и если там есть слово "new" закрывает и запускает поток на обработку данного файла

А зачем? Почему бы не делать все в одном потоке?
 NS

08-01-2008 09:39 | Вопрос к автору: запрос дополнительной информации
Было бы неплохо привести код, который работает с файлом.

Добавьте свое cообщение

Вашe имя:  [Войти]
Ваш адрес (e-mail):На Королевстве все адреса защищаются от спам-роботов
контрольный вопрос:
Какой месяц идет после марта?
в качестве ответа на вопрос или загадку следует давать только одно слово в именительном падеже и именно в такой форме, как оно используется в оригинале.
Надоело отвечать на странные вопросы? Зарегистрируйтесь на сайте.
Тип сообщения:
Текст:
Жирный шрифт  Наклонный шрифт  Подчеркнутый шрифт  Выравнивание по центру  Список  Заголовок  Разделительная линия  Код  Маленький шрифт  Крупный шрифт  Цитирование блока текста  Строчное цитирование
  • вопрос Круглого стола № XXX

  • вопрос № YYY в тесте № XXX Рыцарской Квинтаны

  • сообщение № YYY в теме № XXX Базарной площади
  • обсуждение темы № YYY Базарной площади
  •  
     Правила оформления сообщений на Королевстве

    Страница избранных вопросов Круглого стола.
      
    Время на сайте: GMT минус 5 часов

    Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter.
    Функция может не работать в некоторых версиях броузеров.

    Web hosting for this web site provided by DotNetPark (ASP.NET, SharePoint, MS SQL hosting)  
    Software for IIS, Hyper-V, MS SQL. Tools for Windows server administrators. Server migration utilities  

     
    © При использовании любых материалов «Королевства Delphi» необходимо указывать источник информации. Перепечатка авторских статей возможна только при согласии всех авторов и администрации сайта.
    Все используемые на сайте торговые марки являются собственностью их производителей.

    Яндекс цитирования