![]()  | 
	
 
  | 
		
			
  | 	
	
	
		
		|||||||
| Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны | 
![]()  | 
	
	
| 
		 | 
	Опции темы | Поиск в этой теме | Опции просмотра | 
| 
		 
			 
			#16  
			
			
			
			
		 
		
		
	 | 
||||
		
		
  | 
||||
| 
	
	
		
			
			 Как совет и не более: 
		
	
		
		
		
		
			
		
		
		
		
	
		
		
	
	
	1) Посчитай сколько веток у дерева; 2) Руби дерево по веткам и кидай каждую ветку в отдельный поток (ветка как новое дерево в потоке, как новый Ref в интерфейсе); 3) Контролируй вложенность каждой срубленной ветки и при необходимости руби на более мелкие ветки; 3) Если дерево с о-о-очень длинным вложениями (ветками) - как вариант создавай очередь потоков; 4) Если дерево "вЕсит" очень много - как вариант разбивай на маленькие деревья и выбрасывай пул на диск, а индексы в ОЗУ. Такой подход займет время на подготовку(парсинг), но существенно ускорит запись/чтение листьев. Может я не правильно понял задачу. Я видел лишь попытку разбора дерева, а что делается с листьями? Куда ложатся данные? Если в одно и то же место - следует ли учесть порядок данных? и т.д.  | 
| Этот пользователь сказал Спасибо Alex_4444 за это полезное сообщение: | ||
 
Uniq! (17.03.2015)
  | ||
| 
		 
			 
			#17  
			
			
			
			
		 
		
		
	 | 
||||
		
		
  | 
||||
| 
	
	
		
			
			 Цитата: 
	
 В конечном итоге я всё разобрал. Мне одноуровневого разбиения на потоки достаточно. Глубже нет смысла разбивать. Листья складируются в 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  
			
			
			
			
		 
		
		
	 | 
||||
		
		
  | 
||||
| 
	
	
		
			
			 Не надо отправлять указатели в поток. Нужно создавать в потоке новое дерево и его там же обрабатывать. Парсинг дерева по первым веткам неизбежен. Ну а дальше: каждая ветка  - нужно создать отдельное дерево в потоке. 
		
	
		
		
		
		
			
		
		
		
		
		
			Очередь задач можно создать классами через TObjectsList. Если можно по-подробнее: куда и как "ложатся" данные (листья)? Нужно ли изменять данные при парсинге? Нужен готовый код или просто направление? Последний раз редактировалось Alex_4444, 17.03.2015 в 16:44.  | 
| 
		 
			 
			#19  
			
			
			
			
		 
		
		
	 | 
||||
		
		
  | 
||||
| 
	
	
		
			
			 Цитата: 
	
 Код не нужен. Я не совсем понимаю. XML уже распаршен (после того как Active := true) , и лежит распаршенный в TXMLDocument (штатный компонент, речь ведь не идёт о ручном парсинге XML? ) Изменять данные не нужно. Модель данных такая: объект, --внутри квартиры, ----внутри комнаты, ------внутри приборы (три поля свойств) Эти свойства просто должны попасть в таблицу MySQL сформировав "Список приборов". С ними больше ничего не должно происходить. Последний раз редактировалось Uniq!, 17.03.2015 в 17:01.  | 
| 
		 
			 
			#20  
			
			
			
			
		 
		
		
	 | 
||||
		
		
  | 
||||
| 
	
	
		
			
			 XML начинает парсинг при активации. А дальше дело техники. 
		
	
		
		
		
		
			
		
		
		
		
	
		
		
	
	
	К сожалению в твоем случае мои предыдущие советы вообще ни к месту. Раз тебе нужно только считать данные, то: 1) выстави свойство XMLDocument1.ParseOptions := [poAsyncLoad]; //это должно активировать нативный механизм потоков парсинга. 2) Перед тем как считывать данные с листьев, проверь готовность парсера через свойство XMLDocument1.AsyncLoadState; //должно быть равно 4 3) Сколько потоков выдержит твой компьютер? Допустим 5. Тогда число веток делим на пять -> создаем пять потоков -> каждому потоку целое + остаток деленный на 5 -> в каждом потоке создаем подключение к БД и пусть варятся в собственном соку))). Как то так.  | 
| 
		 
			 
			#21  
			
			
			
			
		 
		
		
	 | 
||||
		
		
  | 
||||
| 
	
	
		
			
			 Цитата: 
	
 Или я вас неправильно понял? И мне нужно создавать помимо коннекта к БД ещё и отдельный TXMLDocument в каждый поток? Я действительно не понимаю через какую переменную будет происходить взаимодействие. Прошу прощения за тягомотину: Два варианта развития вижу: 1) Каждому потоку в конструктор передаю путь к файлу и номер нужного мне объекта. 2) Каждый поток получает список задач (т.е. в каком-то виде заранее упорядоченные объекты) и сам берёт от туда объект, затирая его после переноса листьев.  | 
| 
		 
			 
			#22  
			
			
			
			
		 
		
		
	 | 
||||
		
		
  | 
||||
| 
	
	
		
			
			 чет я перемудрил, дико извиняюсь))) 
		
	
		
		
		
		
			
		
		
		
		
	
		
		
	
	
	"первому потоку целое + остаток от деления", остальным потокам просто целое)))  | 
| 
		 
			 
			#23  
			
			
			
			
		 
		
		
	 | 
||||
		
		
  | 
||||
| 
	
	
		
			
			 Цитата: 
	
 Нет. В Вашем случае не нужно создавать отдельный документ. Это я виноват - запутал Вас с самого начала, т.к. не понял до конца задачу и решил, что необходимо организовать локальную БД в виде XML-ки. А у Вас, по сути, обычный экспорт значений из XML-ки во внешнюю БД. И, как я понял, нужна скорость.  | 
| 
		 
			 
			#24  
			
			
			
			
		 
		
		
	 | 
||||
		
		
  | 
||||
| 
	
	
		
			
			 Цитата: 
	
 Оба варианта - ресурсоёмкие алгоритмы. Для обычного экспорта не надо всего этого.  | 
| 
		 
			 
			#25  
			
			
			
			
		 
		
		
	 | 
||||
		
		
  | 
||||
| 
	
	
		
			
			 Код: 
	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.  |