![]() |
|
|
Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
![]() |
|
Опции темы | Поиск в этой теме | Опции просмотра |
#1
|
||||
|
||||
![]() У месть есть большой XML файл, который содержит в себе 20-30 структур строительных зданий (nObj - одна структура).
Без потоков я просто беру параметрический цикл: Код:
iObjs := XMLDoc.DocumentElement; for ObjNr := 0 to iObjs.ChildNodes.Count - 1 do begin nObj := iObjs.ChildNodes[ObjNr]; txtObjNr := nObj.ChildValues['T_Number']; txtObjCity := nObj.ChildValues['City']; txtObjAddress := nObj.ChildValues['Street']; // внутренний парсинг конкретного nObj end Медленно. Поэтому решил каждый объект отдать на растерзание парсеру в отдельный поток: Класс потока: Код:
type TObjThread = class(TThread) private sObj: IXMLNode; { Private declarations } protected procedure Execute; constructor Create(nObj: IXMLNode); end; constructor TObjThread.Create(nObj: IXMLNode); begin inherited Create(True); self.sObj := nObj; Resume; end; Код:
for ObjNr := 0 to iObjs.ChildNodes.Count - 1 do begin nObj := iObjs.ChildNodes[ObjNr]; ObjThread := TObjThread.Create(nObj); end Но когда дело доходит до Execute получаю ошибку Код:
Abstract Error. Код:
procedure TObjThread.Execute; var txtObjNr, txtObjCity, txtObjAddress: OleVariant; begin txtObjNr := sObj.ChildValues['T_Number']; txtObjCity := sObj.ChildValues['City']; txtObjAddress := sObj.ChildValues['Street']; end; Что я делаю не так? Чую, что дело в переменной nObj, которая является лишь ссылкой на часть "байт" в структуре iObjs (TXMLDocument),и по факту каждый поток пытается оперировать с одним и тем же TXMLDocument. Последний раз редактировалось Uniq!, 25.02.2015 в 15:19. |
#2
|
|||
|
|||
![]() А почему OnExecute ?
![]() |
#3
|
||||
|
||||
![]() Цитата:
Конструктивно ничего не поменялось ![]() |
#5
|
||||
|
||||
![]() Цитата:
Сейчас в нём 22 объекта, 18 MB. Планируется обслуживать 150 штук, но есть возможность разделить их по группам, тем самым генерируя несколько файлов вместо одного. Архитектурно получается всё достаточно гибко. |
#6
|
||||
|
||||
![]() Цитата:
Не стоит путать форумы с богадельнями. © Bargest |
#7
|
|||
|
|||
![]() Для начала. В потоке COM-подсистему инициализировал (CoInitialize)? Для приложения (читай: главного потока) это для тебя делает Application, а для дочерних потоков надо делать самому.
|
#8
|
||||
|
||||
![]() Код:
type TObjThread = class(TThread) private sObj: IXMLNode; { Private declarations } protected procedure Execute; override; constructor Create(nObj: IXMLNode); end; Жизнь такова какова она есть и больше никакова. Помогаю за спасибо. |
#10
|
||||
|
||||
![]() Работа такая работа, про форум совсем забыл.
Медленно, это около 6ти часов. структура очень жёсткая, много полей и записей. С самой ошибкой я уже разобрался, не хватало Код:
override; Но проблему я так и не смог побороть, чтоб один поток обрабатывал определённую часть файла (читай: один объект). Переводить всё на SAX не имеет смысла, ибо файл всегда можно разделить. Просто из-за хлипкости генерирующего движка приходиться работать по принципу: работает? не трогай! Конкретно сейчас ограничиваюсь имеющимся файлом. Про Код:
CoInitialize |
#11
|
||||
|
||||
![]() Цитата:
А насчет многопоточности -- мож стоит вначале poAsyncLoad в IXMLDocument.ParseOptions установить? Дока говорит, что это якобы должно увеличить производительность. Не стоит путать форумы с богадельнями. © Bargest Последний раз редактировалось Freeman, 05.03.2015 в 18:19. |
#12
|
||||
|
||||
![]() lmikle, огромное спасибо. Справился.
Собрал многопоточное приложение так, как это было необходимо. Наткнулся на проблему: нужно ограничить количество потоков. Прочитал, что нужен менеджер потоков. Массив ограниченной длины, в котором будут жить и умирать потоки. Код получился таким. Чую, что можно проще. С радостью выслушал бы критику. Код:
iObjs := XMLDoc.DocumentElement; SetLength(XMLObjects, iObjs.ChildNodes.Count); for ObjNr := 0 to iObjs.ChildNodes.Count - 1 do XMLObjects[ObjNr] := iObjs.ChildNodes[ObjNr]; while Length(XMLObjects) <> 0 do begin for i := 0 to 4 do begin if (Parser[i] = nil) or (Parser[i].Finished) then begin Parser[i] := TObjectParser.Create (iObjs.ChildNodes[Length(XMLObjects) - 1], i + 1); SetLength(XMLObjects, Length(XMLObjects) - 1); end; end; Application.ProcessMessages; end; XMLObjects[ObjNr] - массив задач, которые нужно выполнить *массив объектов Parser[i] - массив, живущих потоков |
#13
|
||||
|
||||
![]() А я по мотивам этой темы потестировал MSXML на стометровом XML-файле. Программа выжрала порядка 1 ГБ ОЗУ и упала с сообщением о нехватке памяти. А я всего лишь максимальную вложенность тегов посчитать хотел. Теперь раздумываю о написании XML-парсера на основе своей библиотеки для компилятора.
Не стоит путать форумы с богадельнями. © Bargest |
#14
|
|||
|
|||
![]() Цитата:
Не с того конца идешь. я бы сделал очередь заданий и массив потоков. Ну это, в принципе, как у тебя и сделано. А вот дальше я просто сделал бы так, что потоки сами берут задания из очереди и выполняют их (не забудь синхронизацию через критическую секцию). А основной код периодически, например, опрашивает состояние потоков. Как только все потоки Idle, то все сделано. |
#15
|
||||
|
||||
![]() Цитата:
Напичкать его указателями на i-ые объекты И научить свой класс потока общаться с этим листом. Я не понимаю что значит "сами берут задания из очереди". было вот так: я сам передавал ему информацию на обработку. Код:
Parser := TParser.Create(iObjs.ChildNodes[Length(XMLObjects) - 1]); А теперь я так понимаю создаётся поток без параметров. И в методе Execute 1) лочит массив, где лежит информация 2) забирает её к себе на обработку (зануляя при этом ячейку массива 3) разлочит массив. Так что ли? Последний раз редактировалось Uniq!, 15.03.2015 в 20:39. |