![]() |
|
|
Регистрация | << Правила форума >> | 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. |