![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Проблемы с потоками при закачке страниц
Pcrepair © (2012-12-27 11:20:00)Добрый день.
Есть функция вида function LoadPage(const Url:string):string; для закачки страниц на базе idHHP.Get, которая обеспечивает:
- закачку страниц с фреймами
- закачку страниц по HTTPs
- смену Request.UserAgent (доп. функция) по Random из списка агентов
- подавление исключений в коде idHHP.Get с записью в лог причин
- вывод сообщений о утечке памяти при закрытии Арр
Сама по себе функция работает нормально, загружает все страницы и без утечки памяти.
Есть код запуска этой функции в многопоточном режиме:
unit Main;
....
implementation
{$R *.dfm}
uses uLoadPage,uGlobalVar;
(*нажимает эту кнопку и понеслось*)
procedure TMainForm.Btn_StartLoadURLsClick(Sender: TObject);
var
UrlList:TStringList; (*эквивалент передаваемого массива строк из ПМ*)
i:integer;
Url:string; (*строка = УРЛ из массива*)
begin
UrlList:=TStringList.Create;
UrlList.Text:=Mm_InsSMUrls.Text; (*ввод массива строк УРЛ*)
(*----ЦИКЛ мульти закачки страниц по числу УРЛ в Mm_InsSMUrls---*)
for i := 0 to UrlList.Count-1 do
begin
Url:=UrlList[i]; (*передача УРЛ*)
Loader(Url); (*вызов процедуры запуска потока закачки страницы*)
Sleep(10); (*страховка от перегрева процессора а также от толпы потоков, которые мешают друг другу?*)
end;
FreeAndNil(UrlList);
end;
unit uLoadPage;
interface
uses SysUtils, uThreadLoader, Classes;
Procedure Loader(Url:string);
implementation
Procedure Loader(Url:string);
var ThreadLdr: TLoader;
begin
ThreadLdr:=Tloader.Create(True);
ThreadLdr.Priority:=tpNormal;
ThreadLdr.FreeOnTerminate:=True;
ThreadLdr.Url:=Url;
ThreadLdr.Start;
end;
end.
unit uThreadLoader;
interface
uses
System.Classes, idHTTP, SysUtils, Dialogs;
type
TLoader = class(TThread)
private
FUrl:string;
FHtml:string;
{ Private declarations }
protected
procedure Execute; override;
procedure CallStore;
function LoadHtmlCode(const Url:string):string;
public
property Url: string read FUrl write FUrl; (*свойство класа, доступное для всей программы*)
property Html: string read FHtml write FHtml;
end;
implementation
uses uPageLoader, uLoadPage, uGlobalVar;
function TLoader.LoadHtmlCode(const Url:string):string;
begin
Result:=LoadPage(Url); (*вызываем функцию загрузки страницы из uPageLoader*)
end;
procedure TLoader.CallStore;
begin
gStore.Add(Html); (*ввод новой строки в ГлобПерем*)
end;
procedure TLoader.Execute;
begin
Html:=LoadHtmlCode(Url); (*загрузка страницы в Поле Класса(свойство)*)
CS.Enter; (*вход в КС*)
CallStore; (*передаем результат в ГП*)
Cs.Leave; (*выход из КС*)
end;
end.
unit uPageLoader;
interface
uses Classes, SysUtils, idHTTP, StrUtils, IdSSL, IdSSLOpenSSL;
function LoadPage(const Url:string):string; (*Основная функция Юнита*)
procedure ErrorLog(Url:string);
function LoadHtmlPage(const PageUrl:string):string;
function DelJS(const Code:string):string;
function RestoreFrame(const Code:string):string;
function RestoreFullUrl(const Code:string; const RootUrl:string):string;
function GetRandomUserAgent: string;
var
Loader:TidHTTP;
SSL:TIdSSLIOHandlerSocketOpenSSL;
implementation
тут много чего, но все работает, смотри в начало
end.
unit uGlobalVar;
interface
uses Classes, SysUtils, SyncObjs;
var
gStore: TStringList=nil; (*ГП для хранения закачанных страниц*)
CS:TCriticalSection; (*используем КС для передачи результата в основной поток*)
implementation
initialization
gStore:=TStringList.Create;
gStore.Duplicates:=dupAccept;
gStore.Sorted:=False;
Cs:=TCriticalSection.Create;
finalization
FreeAndNil(gStore);
FreeAndNil(CS);
end.
Результат:
В режиме отладки видно что возникает множество самых различных ошибок:
- First chance exception at $00407466. Exception class $C0000005 with message 'access violation at 0x00407466: read of address 0x000000a4'. Process Loader_VER06.exe (2012)
- First chance exception at $7C812AFB. Exception class EIdHTTPProtocolException with message 'Set-Cookie: dle_password=deleted; expires=Tue, 27-Dec-2011 20:37:50 GMT; path=/; domain=.freeseller.ru; httponly'. Process Loader_VER06.exe (2012)
First chance exception at $00629F8C. Exception class $C0000005 with message 'access violation at 0x00629f8c: read of address 0x00000148'. Process Loader_VER06.exe (2012)
- First chance exception at $7C812AFB. Exception class EOSError with message
'System Error. Code: 123. Синтаксическая ошибка в имени файла, имени папки или метке тома'.
Process Loader_VER06.exe (2012)
- First chance exception at $7C812AFB. Exception class EIdNotASocket with message
'Socket Error # 10038
Socket operation on non-socket.'.
Process Loader_VER06.exe (2012)
В рабочем режиме, за счет подавления исключений, все это конечно не вылазит, но:
- закачиваются не все страницы(хотя все УРЛ валидные и функцией закачки закачиваются без вопросов)
- после закрытия Арр выводится сообщение о многочисленных маленьких утечках памяти
По теории потоки не должны пересекаться. каждый имеет свою память. вывод результата через КС. такое впечетление что потоки как то мешают друг другу
Внимание!!! Вопрос: в чем может быть причина появления исключений и утечки памяти именно в режиме многопотоковой закачки?
Pcrepair (2012-12-30 22:40:00) [41]и вот еще что, это исключение есть даже при самом простом коде закачки. один к одному. без всяких потоков. без gStore. без всего
unit uPageLoader;
interface
uses idHTTP, SysUtils;
function LoadPage(const Url:string):string;
var idHttp:TidHTTP;
implementation
function LoadPage(const Url:string):string;
begin
idHttp:=TidHttp.Create(nil);
Result:=idHttp.Get(Url);
FreeAndNil(idHttp);
end;
end.
похоже это косяк ИНДИ
DVM (2012-12-30 22:36:00) [42]
> Pcrepair © (30.12.12 22:21) [58]
> вообще то через это свойство в поток передается УРЛ, как
> оно не может быть public?
А кто говорил, что оно не может быть паблик? На здоровье пусть будет паблик, но оно не потокобезопасно. Сделать потокобезопасное свойство не проблема если что.
> к gStore любые обращения идут через CS, это не сложно
Ну как сказать, везде ли у тебя при любом обращении к любому свойству, любому методу этого gStore сначала происходит вход в крит секцию а потом выход? Это не всегда очевидно.
Pcrepair (2012-12-30 22:21:00) [43]Игорь Шевченко
> Наверное в режиме отладки и строки, на которых проиходит
> исключение, показываются.
SysUtils
procedure ConvertErrorFmt(ResString: PResStringRec; const Args: array of const); local;
begin
raise EConvertError.CreateResFmt(ResString, Args); (*тут*)
end;
Call stack -THread 4064
:7c812afb kernel32.RaiseException + 0x52
System.SysUtils.ConvertErrorFmt($4129A8,(...))
System.SysUtils.StrToInt('')
IdGlobal.IndyStrToInt('')
IdGlobalProtocols.RawStrInternetToDateTime('',0)
IdGlobalProtocols.GMTToLocalDateTime('')
IdHTTPHeaderInfo.TIdEntityHeaderInfo.ProcessHeaders
IdHTTPHeaderInfo.TIdResponseHeaderInfo.ProcessHeaders
IdHTTP.TIdHTTPProtocol.RetrieveHeaders(???)
IdHTTP.TIdCustomHTTP.DoRequest(???,' http://www.xard.ru/post/10305/',nil,$16D3B20,(...))
IdHTTP.TIdCustomHTTP.Get(' http://www.xard.ru/post/10305/',$16D3B20,(...))
IdHTTP.TIdCustomHTTP.Get(' http://www.xard.ru/post/10305/',(...))
IdHTTP.TIdCustomHTTP.Get(' http://www.xard.ru/post/10305/')
uThreadLoader.TLoader.LoadHtmlCode(' http://www.xard.ru/post/10305/')
uThreadLoader.TLoader.LoadPage(' http://www.xard.ru/post/10305/')
uThreadLoader.TLoader.Execute
System.Classes.ThreadProc($16FE0A0)
System.ThreadWrapper($16E13E0)
:7c80b729 ; C:\WINDOWS\system32\kernel32.dll
причем на каждом УРЛ исключение выскакивает дважды
++++++++++++++++++++++++++++++++++++++++++++++++++
> это свойство не потокобезопасно, к нему есть обращения одновременно
> на изменение и чтение из разных потоков?
вообще то через это свойство в поток передается УРЛ, как оно не может быть public? потом значение из этого поля идет в поток и тд...
в конвейре запуска потоков, каждому потоку передается свое значение, после чего поток его обрабатывает. это все
---------------
к gStore любые обращения идут через CS, это не сложно
DVM (2012-12-29 23:28:00) [44]
> Pcrepair © (29.12.12 22:52) [53]
> да уже второй день как есть синхронизация, всего к всему
Да ладно, не верю. Более чем уверен, что вот к этому твоему gStore есть не защищенные обращения.
DVM (2012-12-29 23:26:00) [45]
> Pcrepair © (28.12.12 19:22) [40]
> public
> property Url: string read FUrl write FUrl; (*свойство
> класа, доступное для всей программы*)
это свойство не потокобезопасно, к нему есть обращения одновременно на изменение и чтение из разных потоков?
Игорь Шевченко (2012-12-29 23:12:00) [46]Pcrepair © (29.12.12 20:56) [45]
> для всех пишет одно и то же(в режиме отладки):
> First chance exception at $7C812AFB. Exception class EConvertError
> with message ''''' is not a valid integer value'. Process
> Project.exe (2728)
> Что это непонятно
Наверное в режиме отладки и строки, на которых проиходит исключение, показываются.
Не томи.
Сергей М. (2012-12-29 22:59:00) [47]Если однопоточнаязагрузка (о чем тебе еще в [4] намекнул Вася) этих страниц не вызывает исключения, можешь смело забить на него.
В противном случае ССЗБ.
Pcrepair (2012-12-29 22:52:00) [48]да уже второй день как есть синхронизация, всего к всему
это фигня вылезает на 2-х страницах, всегда одних и тех же, из 200 в списке
кстати, повторюсь, страницы все равно закачиваются, те самые на кторых выскакивает исключение (в режиме отладки только)
Сергей М. (2012-12-29 22:41:00) [49]
> Что это непонятно
Это практически наверняка результат по-прежнему отсутствующей синхронизации обращения твоей дивизии потоков к какому-то общему ресурсу.
Медвежонок Пятачок (2012-12-29 22:36:00) [50]ну значит и эксепшена нет. Наверное тебе привиделось.
Pcrepair (2012-12-29 22:30:00) [51]это ты так очень иносказательно, почти как дедушко Крылов, намекаешь что исключение связано с использованием системной функции?
кстати, нет там нигде StrToInt. и IntToStr то же нет
Медвежонок Пятачок (2012-12-29 21:30:00) [52]А кто тогда делает strtoint? Дедушко мороз?
Медвежонок Пятачок (2012-12-29 21:23:00) [53]А кто тогда делает strtoint? Дедушко мороз?
Pcrepair (2012-12-29 21:18:00) [54]нет в IdHTTP.TIdCustomHTTP.Get никакой обработки.
Медвежонок Пятачок (2012-12-29 21:11:00) [55]Что что. Это твоя обработка текста страницы. К загрузке отношения не имеющая.
Pcrepair (2012-12-29 20:56:00) [56]ну что все уже празднуют? вопросы еще остались
сделал все функции и процедуры методами класса, из доп модулей ничего не вызывается
ошибки остались, только для этих страниц:
----------------это все из отладчика----------------------------------------
IdHTTP.TIdCustomHTTP.Get(' http://www.xard.ru/post/10305/',(...))
IdHTTP.TIdCustomHTTP.Get(' http://www.electrosad.ru/Electronics/PP.htm',$16D3A00,(...))
uThreadLoader.TLoader.LoadHtmlCode(' http://www.xard.ru/post/10305/')
для всех пишет одно и то же(в режиме отладки):
First chance exception at $7C812AFB. Exception class EConvertError with message ''''' is not a valid integer value'. Process Project.exe (2728)
Что это непонятно, так как страницы закачиваются
в остальном все хорошо, утечки памяти нет, закачиваются все страницы
Германн (2012-12-29 02:30:00) [57]Удалено модератором
Pcrepair (2012-12-28 21:45:00) [58]Удалено модератором
Примечание: Правила форума надо уважать
Pcrepair (2012-12-28 21:02:00) [59]Удалено модератором
Сергей М. (2012-12-28 20:05:00) [60]
> constructor TLoader.Create;
> ..
> Self.Priority := tpNormal; // эта строчка гуляет по Тырнету в миллионах экз-рах, ты ее позорно сдул - и какое отношение к себе при этом ты изволишь желать ?
>..
> end;