Форум по Delphi программированию

Delphi Sources



Вернуться   Форум по Delphi программированию > Все о Delphi > [ "Начинающим" ]
Ник
Пароль
Регистрация <<         Правила форума         >> FAQ Пользователи Календарь Поиск Сообщения за сегодня Все разделы прочитаны

Ответ
 
Опции темы Поиск в этой теме Опции просмотра
  #16  
Старый 16.03.2015, 17:06
Аватар для Alex_4444
Alex_4444 Alex_4444 вне форума
Прохожий
 
Регистрация: 22.12.2014
Сообщения: 14
Версия Delphi: XE5
Репутация: 50
По умолчанию

Как совет и не более:
1) Посчитай сколько веток у дерева;
2) Руби дерево по веткам и кидай каждую ветку в отдельный поток (ветка как новое дерево в потоке, как новый Ref в интерфейсе);
3) Контролируй вложенность каждой срубленной ветки и при необходимости руби на более мелкие ветки;
3) Если дерево с о-о-очень длинным вложениями (ветками) - как вариант создавай очередь потоков;
4) Если дерево "вЕсит" очень много - как вариант разбивай на маленькие деревья и выбрасывай пул на диск, а индексы в ОЗУ.
Такой подход займет время на подготовку(парсинг), но существенно ускорит запись/чтение листьев.

Может я не правильно понял задачу. Я видел лишь попытку разбора дерева, а что делается с листьями? Куда ложатся данные? Если в одно и то же место - следует ли учесть порядок данных? и т.д.
__________________
Самые сильные программисты были на заре компьютеризации.
И чем дольше я программист, тем больше это понимаю - мы до сих пор поддерживаем их код...
Ответить с цитированием
Этот пользователь сказал Спасибо Alex_4444 за это полезное сообщение:
Uniq! (17.03.2015)
  #17  
Старый 17.03.2015, 10:12
Аватар для Uniq!
Uniq! Uniq! вне форума
Местный
 
Регистрация: 29.09.2010
Сообщения: 539
Версия Delphi: Delphi XE3
Репутация: 374
По умолчанию

Цитата:
Сообщение от Alex_4444
Может я не правильно понял задачу. Я видел лишь попытку разбора дерева, а что делается с листьями? Куда ложатся данные? Если в одно и то же место - следует ли учесть порядок данных? и т.д.

В конечном итоге я всё разобрал. Мне одноуровневого разбиения на потоки достаточно.
Глубже нет смысла разбивать. Листья складируются в ADODataSet (MySQL таблица) созданный каждый в своём потоке.

Работает всё ужасно не стабильно и криво. Сейчас я сохраняю каждую ветку XML в массив.
Передаю определённую элемент массива в поток, и кладу этот поток в другой массив (определённо длины).
Пока первый массив не иссякнет так и гоняю.

Время от времени появляются ошибки доступа к памяти.
И что-то мне подсказывает, что нельзя таким образом работать с объектом XMLDocument.

Код:
  FormMain.XMLDoc.FileName := LOKAL_DIR + 'XML\' + FileName;
  FormMain.XMLDoc.Active := true;

  Objects := FormMain.XMLDoc.DocumentElement;
  SetLength(ObjectsArr, Objects.ChildNodes.Count);
  for ObjNr := 0 to Objects.ChildNodes.Count - 1 do
    ObjectsArr[ObjNr] := Objects.ChildNodes[ObjNr];

  while Length(ObjectsArr) > 0 do
    for ObjNr := 0 to 4 do
      if (ParsersArr[ObjNr] = nil) or (ParsersArr[ObjNr].Finished) then
      begin
        temp := Length(ObjectsArr) - 1;
        ParsersArr[ObjNr] := TParser.Create(ObjectsArr[temp]);
        SetLength(ObjectsArr, (Length(ObjectsArr) - 1));
      end;

Кто-нибудь может объяснить, как воспользоваться конструкцией для создания Очереди задач?
Код:
function TForm1.DoWorkForQueue(aQueue: TThreadList): boolean;
begin
  with aQueue.LockList do
    try
      Result := not(Count = 0);
    finally
      aQueue.UnlockList;
    end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  Queue: TThreadList;
  Pool: TThreadList;
  objNo: integer;
const
  MaxThreadCount = 5;
begin
  Queue := TThreadList.Create;
  try
    for objNo := 0 to XMLDoc.DocumentElement.ChildNodes.Count - 1 do
      Queue.Add(XMLDoc.DocumentElement.ChildNodes[objNo]); // Ошибка соответствия Типов TPointer и IXMLNode

    while DoWorkForQueue(Queue) do
    begin
      Pool := TThreadList.Create;
      with Pool.LockList do
        try
          if Count < MaxThreadCount then
            Add(TXmlToSql.Create(Queue));
        finally
          Pool.UnlockList;
        end;
     end;

  finally
    Queue.Free;
  end;
end;

Я понять не могу как передать TPointer на кусок XML'я в TThreadList.

Imlike, к вам ещё вопрос:
Стоит ли хранить потоки в таком же списке для их "подсчёта"?
Или просто завести глобальную переменную для их подсчёта (инкрементировать при создании, и декрементировать при уничтожении потока)

Последний раз редактировалось Uniq!, 17.03.2015 в 16:04.
Ответить с цитированием
  #18  
Старый 17.03.2015, 16:32
Аватар для Alex_4444
Alex_4444 Alex_4444 вне форума
Прохожий
 
Регистрация: 22.12.2014
Сообщения: 14
Версия Delphi: XE5
Репутация: 50
По умолчанию

Не надо отправлять указатели в поток. Нужно создавать в потоке новое дерево и его там же обрабатывать. Парсинг дерева по первым веткам неизбежен. Ну а дальше: каждая ветка - нужно создать отдельное дерево в потоке.
Очередь задач можно создать классами через TObjectsList.
Если можно по-подробнее: куда и как "ложатся" данные (листья)?
Нужно ли изменять данные при парсинге?
Нужен готовый код или просто направление?
__________________
Самые сильные программисты были на заре компьютеризации.
И чем дольше я программист, тем больше это понимаю - мы до сих пор поддерживаем их код...

Последний раз редактировалось Alex_4444, 17.03.2015 в 16:44.
Ответить с цитированием
  #19  
Старый 17.03.2015, 16:59
Аватар для Uniq!
Uniq! Uniq! вне форума
Местный
 
Регистрация: 29.09.2010
Сообщения: 539
Версия Delphi: Delphi XE3
Репутация: 374
По умолчанию

Цитата:
Сообщение от Alex_4444
Не надо отправлять указатели в поток. Нужно создавать в потоке новое дерево и его там же обрабатывать. Парсинг дерева по первым веткам неизбежен. Ну а дальше: каждая ветка - нужно создать отдельное дерево в потоке.
Очередь задач можно создать классами через TObjectsList.
Если можно по-подробнее: куда и как "ложатся" данные (листья)?
Нужно ли изменять данные при парсинге?
Нужен готовый код или просто направление?

Код не нужен.

Я не совсем понимаю. XML уже распаршен (после того как Active := true) , и лежит распаршенный в TXMLDocument (штатный компонент, речь ведь не идёт о ручном парсинге XML? )

Изменять данные не нужно.
Модель данных такая:
объект,
--внутри квартиры,
----внутри комнаты,
------внутри приборы (три поля свойств)
Эти свойства просто должны попасть в таблицу MySQL сформировав "Список приборов".
С ними больше ничего не должно происходить.

Последний раз редактировалось Uniq!, 17.03.2015 в 17:01.
Ответить с цитированием
  #20  
Старый 17.03.2015, 17:57
Аватар для Alex_4444
Alex_4444 Alex_4444 вне форума
Прохожий
 
Регистрация: 22.12.2014
Сообщения: 14
Версия Delphi: XE5
Репутация: 50
По умолчанию

XML начинает парсинг при активации. А дальше дело техники.
К сожалению в твоем случае мои предыдущие советы вообще ни к месту.
Раз тебе нужно только считать данные, то:
1) выстави свойство XMLDocument1.ParseOptions := [poAsyncLoad]; //это должно активировать нативный механизм потоков парсинга.
2) Перед тем как считывать данные с листьев, проверь готовность парсера через свойство XMLDocument1.AsyncLoadState; //должно быть равно 4
3) Сколько потоков выдержит твой компьютер? Допустим 5. Тогда число веток делим на пять -> создаем пять потоков -> каждому потоку целое + остаток деленный на 5 -> в каждом потоке создаем подключение к БД и пусть варятся в собственном соку))).
Как то так.
__________________
Самые сильные программисты были на заре компьютеризации.
И чем дольше я программист, тем больше это понимаю - мы до сих пор поддерживаем их код...
Ответить с цитированием
  #21  
Старый 17.03.2015, 20:19
Аватар для Uniq!
Uniq! Uniq! вне форума
Местный
 
Регистрация: 29.09.2010
Сообщения: 539
Версия Delphi: Delphi XE3
Репутация: 374
По умолчанию

Цитата:
Сообщение от Alex_4444
каждому потоку целое + остаток деленный на 5
По вашим словам я должен из потока обращаться к XMKDocument.ChildNodes[i], где i Это номер необходимой ветке (Как его считать другой вопрос).
Или я вас неправильно понял? И мне нужно создавать помимо коннекта к БД ещё и отдельный TXMLDocument в каждый поток?

Я действительно не понимаю через какую переменную будет происходить взаимодействие. Прошу прощения за тягомотину:

Два варианта развития вижу:
1) Каждому потоку в конструктор передаю путь к файлу и номер нужного мне объекта.
2) Каждый поток получает список задач (т.е. в каком-то виде заранее упорядоченные объекты) и сам берёт от туда объект, затирая его после переноса листьев.
Ответить с цитированием
  #22  
Старый 18.03.2015, 05:02
Аватар для Alex_4444
Alex_4444 Alex_4444 вне форума
Прохожий
 
Регистрация: 22.12.2014
Сообщения: 14
Версия Delphi: XE5
Репутация: 50
По умолчанию

чет я перемудрил, дико извиняюсь)))
"первому потоку целое + остаток от деления", остальным потокам просто целое)))
__________________
Самые сильные программисты были на заре компьютеризации.
И чем дольше я программист, тем больше это понимаю - мы до сих пор поддерживаем их код...
Ответить с цитированием
  #23  
Старый 18.03.2015, 05:12
Аватар для Alex_4444
Alex_4444 Alex_4444 вне форума
Прохожий
 
Регистрация: 22.12.2014
Сообщения: 14
Версия Delphi: XE5
Репутация: 50
По умолчанию

Цитата:
Сообщение от Uniq!

И мне нужно создавать помимо коннекта к БД ещё и отдельный TXMLDocument в каждый поток?

Нет. В Вашем случае не нужно создавать отдельный документ.
Это я виноват - запутал Вас с самого начала, т.к. не понял до конца задачу и решил, что необходимо организовать локальную БД в виде XML-ки.

А у Вас, по сути, обычный экспорт значений из XML-ки во внешнюю БД. И, как я понял, нужна скорость.
__________________
Самые сильные программисты были на заре компьютеризации.
И чем дольше я программист, тем больше это понимаю - мы до сих пор поддерживаем их код...
Ответить с цитированием
  #24  
Старый 18.03.2015, 05:35
Аватар для Alex_4444
Alex_4444 Alex_4444 вне форума
Прохожий
 
Регистрация: 22.12.2014
Сообщения: 14
Версия Delphi: XE5
Репутация: 50
По умолчанию

Цитата:
Сообщение от Uniq!
Два варианта развития вижу:
1) Каждому потоку в конструктор передаю путь к файлу и номер нужного мне объекта.
2) Каждый поток получает список задач (т.е. в каком-то виде заранее упорядоченные объекты) и сам берёт от туда объект, затирая его после переноса листьев.

Оба варианта - ресурсоёмкие алгоритмы.
Для обычного экспорта не надо всего этого.
__________________
Самые сильные программисты были на заре компьютеризации.
И чем дольше я программист, тем больше это понимаю - мы до сих пор поддерживаем их код...
Ответить с цитированием
  #25  
Старый 18.03.2015, 09:06
Аватар для Alex_4444
Alex_4444 Alex_4444 вне форума
Прохожий
 
Регистрация: 22.12.2014
Сообщения: 14
Версия Delphi: XE5
Репутация: 50
По умолчанию

Код:
unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Xml.xmldom, Xml.XMLIntf, Vcl.StdCtrls,
  Xml.Win.msxmldom, Xml.XMLDoc;

type
  TForm1 = class(TForm)
    XMLDocument1: TXMLDocument;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
    procedure AreYouReady(Sender: TObject; AsyncLoadState : integer);
    procedure LetsCreateOurThreads;
  public
    { Public declarations }
  end;

  MyThread = class(TThread)
  private
    FCountNodes : integer;
    FStartNode  : integer;
    FEndNode    : integer;
    FNode       : IXMLNode;
  protected
    procedure Execute; override;
  public
    constructor Create(CountNodes, StartNode: integer;
                       Node: IXMLNode; CreateSuspended: Boolean);
    destructor Destroy; override;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}



procedure TForm1.AreYouReady(Sender: TObject; AsyncLoadState: integer);
begin
  if AsyncLoadState = 4 then
    begin
      LetsCreateOurThreads;
    end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  XMLDocument1.FileName := '';
  XMLDocument1.ParseOptions := [poAsyncLoad]; // это должно активировать
                                              // нативный механизм потоков
                                              // парсинга. За нас уже всё продумано.
  XMLDocument1.OnAsyncLoad := AreYouReady;    // т.к. парсинг в нативных потоках,
                                              // то необходимо дождаться его.
  XMLDocument1.Active := true;
end;

procedure TForm1.LetsCreateOurThreads;
var
  MyNode : IXMLNode;
  i,
  childCount,
  whole,
  modulo,
  start,
  threadCount : integer;
  tempThread : MyThread;
begin
  threadCount := 5; // максимальное количество одновременно работающих потоков
  MyNode := XMLDocument1.DocumentElement;
  childCount := MyNode.ChildNodes.Count;
  whole  := childCount div threadCount; // количество веток на один поток
  modulo := childCount mod threadCount; // остаток веток - мы его в первый поток отдадим
  // Создаем первый поток
  // можно да и нужно создавать TtreadList для контроля за потоками но я пропустил его
  // для наглядности кода
  tempThread := MyThread.Create(whole + modulo - 1, 0, MyNode, false);
  start := whole + modulo;
  if childCount > 1 then
    begin
      for i := 2 to ThreadCount do
        begin
          tempThread := MyThread.Create(whole, start, MyNode, false);
          start := start + whole;
        end;
    end;
end;

{ MyThread }

constructor MyThread.Create(CountNodes, StartNode: integer;
                            Node: IXMLNode; CreateSuspended: Boolean);
begin
  inherited Create(CreateSuspended);
  FNode       := Node;
  FCountNodes := CountNodes;
  FStartNode  := StartNode;
  FEndNode    := StartNode + CountNodes;
  // здесь создашь все коннекты: к БД и т.п
end;

destructor MyThread.Destroy;
begin
  // здесь удалишь все коннекты: к БД и т.п.
  inherited;
end;

procedure MyThread.Execute;
var
  i : integer;
  tempNode : IXMLNode;
  txtObjNr,
  txtObjCity,
  txtObjAddress : string;
begin
  for i := FStartNode to FEndNode do
    begin
        tempNode := FNode.ChildNodes[i];
        txtObjNr := tempNode.ChildValues['T_Number'];
        txtObjCity := tempNode.ChildValues['City'];
        txtObjAddress := tempNode.ChildValues['Street'];
        // и выкидывай txtObj--- в базу данных
    end;
  //если всё норм выходи из потока
end;

end.

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

Последний раз редактировалось Alex_4444, 18.03.2015 в 09:28.
Ответить с цитированием
Ответ


Delphi Sources

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

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

BB-коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход


Часовой пояс GMT +3, время: 11:14.


 

Сайт

Форум

FAQ

Соглашения

Прочее

 

Copyright © Форум "Delphi Sources" by BrokenByte Software, 2004-2025