Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 2013.09.22;
Скачать: [xml.tar.bz2];

Вниз

Загрузчик на idHTTP зависает при загрузке страниц   Найти похожие ветки 

 
Pcrepair ©   (2013-01-07 03:14) [0]

Добрый день. Есть код загрузчика страниц(вызывается в поток):

function TLoader.LoadHtmlCode(const PageUrl: String):string;
var
ErrorData:string; (*ответ сервера в тестовом виде*)
ResponseCode:integer; (*ответ сервера в виде кода ошибки*)
begin
  try
    (*---------настройка параметров закачки-----------*)
    FIdHttp.Request.UserAgent:=GetRandomUserAgent; (*получаем случайное значение Юзер-Агент*)
    FIdHttp.Request.AcceptLanguage:="ru-ru,ru;q=0.8,en-us;q=0.5,en;q=0.3"; (*вроде нужно*)
    FIdHttp.Request.AcceptCharSet:="windows-1251,utf-8;q=0.7,*;q=0.3"; (*вроде нужно*)
    FIdHttp.ConnectTimeout:=10000;
    FIdHttp.ReadTimeout:=10000;
    FIdHttp.IOHandler:=FSSL;
    FIdHttp.HandleRedirects:=True;
    Result:=AnsiLowerCase(FIdHttp.Get(PageUrl));
      except
        Result:=PageUrl;
        (*тут вызов ПРОЦ для записи ответа сервера и УРЛ в лог*)
      end;
     Exit;  (*выход из функции. в РЕЗУЛЬТАТ содержится последнее значение*)
  end;
end;

1. При высокой скорости трафика все работает нормально:
- загрузка 100 УРЛ за 20...25 сек (10 потоков одновременно)
- никаких утечек памяти
практически все как предначертано работает
2. При наличие потребителя трафика(другой РС в сети с работающим ТОРРЕНТ, источник интернета - роутер 3 мбит\сек):
- загрузка 97...100 УРЛ за 60...120 сек
- один или два потока зависают(есть на форме индикатор числа работающих потоков)при закачке УРЛ и могут висеть часами, пока не закрыть программу
- никакой зависимости от УРЛ нет, в одном тесте одни УРЛ не закачиваются в другом другие
- еще одна особенность: в логе фиксируется ответ сервера. при наличие конкурента на трафик от 10 до 30 УРЛ не загружаются(то же различные, от теста к тесту), хотя ответ сервера = 200 (ну это не самая большая проблема, скоро будет добавлен код перезакачки УРЛ), но о чем то этот факт говорит?

Внимание! Вопросы:
1. в чем причина такого поведения TidHttp?
возможно надо что то настроить в параметрах загрузчика?
2. возможно ли ввести в поток загрузчика таймер типа:

procedure TLoader.Execute;
begin
 CallTimer;
 FIdHttp.Get(PageUrl);
end;

procedure TLoader.CallTimer;
begin
 (*тут реализация таймера на 100 сек, но на чем? TTimer явно не подойдет*)
  Событие OnTimer вызывает
  FIdHttp.Socket.Close; (*если через 100 сек страница не закачается и поток не сдохнет
  принудительно закрыть idHTTP, поток после тоже закроется*)
  может кто подскажет реализацию таймера, на чем бы его сделать?
end;


почитал на форумах что нашел, похоже таймер единственный вариант решить эту проблему


 
sniknik ©   (2013-01-07 13:03) [1]

внимание! ответы:
1: у тебя ошибка в программе... где хз. т.к. если убрать всю "мишуру" из "примера проблемного кода" останется только IdHttp.Get с игнорированием ошибки от него (из чего, и твоего "психо портрета", следует - что это за ошибка мы так никогда не узнаем...)
2: во первых возможно, во вторых не нужно... у тебя там и так (ИМХО) перебор с потоками. они не панацея они инструмент. а ты их пихаешь/пытаешься куда не попадя. если так уж хочется таймер то поставь его с главной формы.... один на все, в основном потоке, он же у тебя свободен, нет? сделать диспетчеризацию с проверкой таймаута можно и оттуда.


 
sniknik ©   (2013-01-07 13:13) [2]

кстати, т.к. ошибка игнорируется т.е. блокируется и дает "развернуть цепочку" то возможно "зависание" это попросту ожидание реакции (ответа или эксепта) где нибудь в связанных компонентах (например FSSL).
... есть еще одно на что оно среагирует, на закрытие коннекта, и не в вынесенном таймере, а прямо в коде после исполнения/глюка.

блин, чего я распинаюсь, ты же "необучаем"... может просто - закрывай коннект (FIdHttp.Disconnect) в LoadHtmlCode перед последним end;.


 
Pcrepair ©   (2013-01-07 13:59) [3]


> блин, чего я распинаюсь, ты же "необучаем"... может просто
> - закрывай коннект (FIdHttp.Disconnect) в LoadHtmlCode перед
> последним end;.

теория интересная, но.....
1. подобный вопрос уже обсуждался на разных форумах, пришли к выводу что это текущий глюк ИНДИ(GET не отрабатывает при некоторых условиях, в данном случае из за маленькой скорости трафика и некоторых настроек некоторых веб-серверов, которые не отдают контент и не разрывают соединение)
2. не надо предлагать как лучше. идет процесс обучения. в ланный момент хочю попробовать запустить таймер в ПОТОКЕ
итак еще разок:
как же сделать таймер в потоке? никто не знает!?


 
Медвежонок Пятачок ©   (2013-01-07 15:05) [4]

неужели надо вызвать конструктор таймера?
ужас.
кто бы мог подумать, что и в потоке все точно так же как и в главном потоке.


 
Pcrepair ©   (2013-01-07 15:23) [5]

какого таймера конструктор?
везде пишут что TTimer в потоке лучше не использовать
выражай мысли поточнее, если не сложно


 
DVM ©   (2013-01-07 15:23) [6]


> Pcrepair ©

1. У IdHTTP есть свойства ReadTimeout и ConnectTimeOut. Это первое. Они позволят при недоступном или не отвечающем сервере не висеть вечно.
2. Если поток, осуществляющий закачку по каким то причинам повис на очень-очень медленном ответе сервера, то закачку всегда можно прервать сделав сокету от TidHTTP Close, но из другого потока (предварительно убедившись, что сокет вообще есть).


 
DVM ©   (2013-01-07 15:26) [7]


> Pcrepair ©


> 2. не надо предлагать как лучше. идет процесс обучения.
> в ланный момент хочю попробовать запустить таймер в ПОТОКЕ
> итак еще разок:
> как же сделать таймер в потоке? никто не знает!?

все знают, кто хоть раз вместо форума открывал справку от TTimer или раздел MSDN где говорится про функцию SetTimer. Но нужен ли там тебе таймер? Тем более что его работа в доп потоке будет блокирована тем же блокирующим Indy


 
Медвежонок Пятачок ©   (2013-01-07 15:27) [8]

везде пишут что TTimer в потоке лучше не использовать
выражай мысли поточнее, если не сложно


Ты же кровь из носу хотел создать именно таймер и именно в потоке.

как же сделать таймер в потоке? никто не знает

Теперь тебе сказали как создать таймер в потоке.


 
sniknik ©   (2013-01-07 16:25) [9]

> теория интересная
это не теория... это аксиома (факт). вот если бы ты вместо сказанного исправил код, отловил, и привел сюда реально происходящую ошибку... тогда бы можно было сказать что обучение туго, но идет.
а так как нет, то - "необучаем".

> везде пишут что TTimer в потоке лучше не использовать
смысла в нем там нет, это же поток. и сделать его там мало, нужно (главное) цикл сообщений организовать ... где ты встретишься с теми же проблемами от которых говоришь хочешь избавится. и что дальше? еще поток, в потоке, запущенном из потока диспетчера потоков?
лучше бы логику событийную пытался понять, а не писал "линейно" впихивая везде потоки.

DVM ©   (07.01.13 15:23) [6]
>> Pcrepair ©
> 1. У IdHTTP есть свойства ReadTimeout и ConnectTimeOut. Это первое. Они позволят при недоступном или не отвечающем сервере не висеть вечно.
у него они используются, эти свойства..., проблема не в них а где то в ЕГО коде, который типа "много, но работает" и поэтому можно не приводить.


 
Pcrepair ©   (2013-01-07 19:36) [10]

вот если бы ты вместо
> сказанного исправил код, отловил, и привел сюда реально
> происходящую ошибку... тогда бы можно было сказать что обучение
> туго, но идет.
> а так как нет, то - "необучаем".

так ведь нету ошибки
метод GET просто не продолжает что то ждать от сервера
я вводил обработку исключения E:EIdHTTPProtocolException но исключения просто небыло.
логика событий крайне простая:
- нажимаем кнопку "ПУСК"
- вызывается основной поток управления потоками(это чтоб таймер на форме не подвисал), получает список УРЛ(ну до 1000)
- основной поток запускает цикл создания потоков закачки(внутри экземпляр idhttp) +1 в счетчик потоков
- потоки закачивают и передают результат в ГП и стетчик потоков уменьшают на 1
- основной поток считает сколько потоков в наличии чтоб больше 10 не было, один закончил работу, дозапускается еще один
но это все делается без учета ИД потоков, просто есть ГП типа ЧИСЛО

Всетаки проблема в idHTTP. была слабая надежда что можно как то в самом экземпляре потока все сделать. так чтобы отработал 300 сек и отключился, неважно отработало ли idhttp.get


 
Сергей М. ©   (2013-01-07 19:56) [11]


> нету ошибки
> метод GET просто не продолжает что то ждать от сервера


Что значит "не продолжает ждать" ?
Прямо так и говорит "не хочу больше ждать, я устал" ?


 
Сергей М. ©   (2013-01-07 19:58) [12]


> исключения просто небыло


Если исключения (не важно какого) не было, значит метод либо продолжает выполнение либо успешно выполнен.


 
Pcrepair ©   (2013-01-07 20:10) [13]

Что значит "не продолжает ждать" ? = продолжает ждать
ага метод продолжает выполнение, час продолжает. два продолжает
вот и надо через 300 сек поток принудительно грохнуть, всему есть разумный предел


 
brother ©   (2013-01-07 20:12) [14]

> ага метод продолжает выполнение, час продолжает. два продолжает

почему нет? ты проверял, что он там делает все это время?


 
Сергей М. ©   (2013-01-07 20:15) [15]


> вот и надо через 300 сек поток принудительно грохнуть


Ну так и установи ReceiveTimeout и ConnectTimeout = 300 сек !

Через 300 сек получишь отлуп в виде EIdReadTimeout или EIdConnectTimeout - и делай в обработчике исключения нужные тебе телодвижения.


 
sniknik ©   (2013-01-07 21:13) [16]

> исключения просто небыло
не было или ты его не видел? т.к. благополучно проигнорировал (в приведенном коде).
"позиция страуса" - не вижу значит не существует. закрою глаза значит не бывает.

p.s. ты на самом деле ни хрена не понимаешь? может тебе не с потоков, с основ начать? ну там, объекты, операции, события, исключения...

> Через 300 сек получишь отлуп
не все так просто, бывают варианты (версия/ssl) неправильного "тайминга"
http://delphimaster.net/view/6-1287562673/
но на "крайняк" получит через 900 сек (или ставить 100 сек).


 
sniknik ©   (2013-01-07 21:15) [17]

кстати, а что там перекачивается, что аж 5 мин требуется ждать?


 
Pcrepair ©   (2013-01-07 21:30) [18]

да ничего такого
просто программа должна выдавать результат с мнимимальным временем отклика

> Ну так и установи ReceiveTimeout и ConnectTimeout = 300
> сек !
>
> Через 300 сек получишь отлуп в виде EIdReadTimeout или EIdConnectTimeout
> - и делай в обработчике исключения нужные тебе телодвижения.
>


так и установил в 100 сек. но не грохается
а ссылка интересная. получается это все мелкие косячки инди


> почему нет? ты проверял, что он там делает все это время?

а ничего не делает. просто висит. и как это можно проверить? если GET так и не закончил работу.


 
Anatoly Podgoretsky ©   (2013-01-07 21:36) [19]

> sniknik  (07.01.2013 21:13:16)  [16]

C азов это очень сложно.


 
DVM ©   (2013-01-07 21:38) [20]


> Pcrepair ©   (07.01.13 19:36) [10]


> так ведь нету ошибки

Согласен со sniknik, скорее всего ты задавил где то исключение благополучно вот и нет его. Ты лучше дай URL на котором гарантированно такое происходит, я возьму TidHTTP и выполню Get для данного URL и получу зависание. И все станет ясно.

Учитывая предыдущие твои вопросы еще рискну предположить, что у нас опять может иметь место проблема синхронизации между потоками.

Прервать любую операцию с сокетами можно без проблем закрыв сокет из другого потока. Если возвратиться к теме пула потоков, то вот этот самый менеджер потоков в отдельном потоке мог бы проверять, сколько времени работает тот или иной поток и если работа затянулась - закрывать соответствующий сокет, че бы там ни было, вылетит исключение и закачка прервется.


 
Сергей М. ©   (2013-01-07 21:43) [21]


> установил в 100 сек. но не грохается


и для ConnectTimeout тоже ?


 
DVM ©   (2013-01-07 21:45) [22]


> Pcrepair ©   (07.01.13 21:30) [18]


> получается это все мелкие косячки инди

Не стоит торопиться с выводами, косячки есть конечно, они исправляются, например со времен той ветки многое исправилось.


 
DVM ©   (2013-01-07 21:48) [23]


>  еще рискну предположить, что у нас опять может иметь место
> проблема синхронизации между потоками.

вот, например,


     except
       Result:=PageUrl;
       (*тут вызов ПРОЦ для записи ответа сервера и УРЛ в лог*)
     end;


Эта самая ПРОЦ она синхронизирует доступ к логу?


 
Pcrepair ©   (2013-01-07 21:49) [24]


> Ты лучше дай URL на котором гарантированно такое происходит,
>  я возьму TidHTTP и выполню Get для данного URL и получу
> зависание. И все станет ясно.

сверху написано - в каждом цикле загрузки сбойные УРЛ разные
к тому же этот косяк проявляется только при многопоточной загрузке и ТОЛЬКО когда трафик занят закачкой тореннта и не просто торрента а с ЛОСТФИЛЬМ

вся синхронизация идет через КС - куда больше? да там и всех делов: вывод страницы в накопитель(СПИСОК)

исключение тут:

Result:=AnsiLowerCase(FIdHttp.Get(PageUrl));
    except (*да иск макс уровня*)
        Result:=PageUrl+(" = Total Error");
        ErrorData:=FIdHttp.Response.ResponseText;
       (*----27.12.2012 синхронизация через КС--------*)
         CS.Enter;  (*вход в КС*)
           ErrorLog(PageUrl+#10+ErrorData); (*только для контроля*)
         Cs.Leave;  (*выход из КС*)
       (*---------------------------------------------*)
       Exit;
  end;
end;

вообще в этой теме хотелось рассмотреть возможность самоликвидации потока по времени
менеджер рассмотрим в другой теме. если будут вопросы


 
Pcrepair ©   (2013-01-07 21:51) [25]


> и для ConnectTimeout тоже ?

само собой


 
DVM ©   (2013-01-07 21:53) [26]


> Pcrepair ©   (07.01.13 21:49) [24]

 (*----27.12.2012 синхронизация через КС--------*)
         CS.Enter;  (*вход в КС*)
           ErrorLog(PageUrl+#10+ErrorData); (*только для контроля*)
         Cs.Leave;  (*выход из КС*)
       (*---------------------------------------------*)

че такое CS ? Это поле класса TLoader? Если да, подравляю тебя у тебя доступ к логу не синхронизован.


 
Сергей М. ©   (2013-01-07 21:53) [27]


> само собой


И при этом ты убедился что соединение действительно установлено, но трафик по нему нулевой (или ненулевой, но не прогрессирует) ?


 
DVM ©   (2013-01-07 22:00) [28]


> Pcrepair ©   (07.01.13 21:49) [24]


> вообще в этой теме хотелось рассмотреть возможность самоликвидации
> потока по времени

Если поток блокирован какой то операцией то он не может самоликвидироваться, он же не мюнхаузен, чтобы сам себя вытащить из болота. А вот выйти ему из состояния блокировки (если блокировку действительно вызывает Indy) можно закрыв сокет извне, чего непонятного то?
Нужен внешний менеджер который будет потоки мониторить.


 
Pcrepair ©   (2013-01-07 22:06) [29]


> че такое CS ? Это поле класса TLoader? Если да, подравляю
> тебя у тебя доступ к логу не синхронизован.

это конечно ГлобПерем

> И при этом ты убедился что соединение действительно установлено,
>  но трафик по нему нулевой (или ненулевой, но не прогрессирует)
> ?

ну вообще есть вот такой эффект(повтор заголовка темы):
При наличие потребителя трафика(другой РС в сети с работающим ТОРРЕНТ, источник интернета - роутер 3 мбит\сек):
- загрузка 97...100 УРЛ за 60...120 сек
- один или два потока зависают(есть на форме индикатор числа работающих потоков)при закачке УРЛ и могут висеть часами, пока не закрыть программу
- никакой зависимости от УРЛ нет, в одном тесте одни УРЛ не закачиваются в другом другие
- еще одна особенность: в логе фиксируется ответ сервера. при наличие конкурента на трафик от 10 до 30 УРЛ не загружаются(то же различные, от теста к тесту), хотя ответ сервера = 200
это отсюда ErrorData:=FIdHttp.Response.ResponseText;(*тут ответ сервера*)


 
Сергей М. ©   (2013-01-07 22:14) [30]


> ну вообще есть вот такой эффект


Причем здесь "эффект" ?

Я спрашиваю в каком состоянии находится соединение, создаваемое неким "зависшим" IdHTTP ?
NetStat что говорит по этому поводу ?


 
DVM ©   (2013-01-07 22:14) [31]


> Pcrepair ©   (07.01.13 22:06) [29]

Очень много скользких мест.

Вот хотя бы фраза:

есть на форме индикатор числа работающих потоков

А доступ к индикатору синхронизован? Кто и как обновляет его? Откуда уверенность что там верное значение?

Загрузка сети просто ускорят проявление проблем, но они имхо не связаны с загрузкой.


 
sniknik ©   (2013-01-07 22:19) [32]

> Нужен внешний менеджер который будет потоки мониторить.
а кто проверяет проверяющего?

в смысле, проблема в его способе программирования (синхронизация, игнорирование эксептов, ets. х.з. что), он вместо определения что это "навернет" тем же способом еще уровень из потоков... что делать когда подобное возникнет уже на этом уровне?

> ErrorData:=FIdHttp.Response.ResponseText;
вопрос. что это? вот если нет ответа, даже ошибочного от сервера, эксепт же произошёл, кто знает откуда, на каком этапе, например не доходя еще до собственно запроса, и тут идет попытка считать этот ответ... что будет? там же не просто переменная, там возможно свойство, с собственным обработчиком...
(не хочу смотреть сам, да и негде сейчас, новый комп, т.что чисто теоретически, на мысль навести...)

p.s. есть же нормальное сообщение в эксепте. почему не использовать его (+ там есть случаи реальных ошибок сервера 400/404/... они отдельно в инди вроде. ну это после добавить). зачем сразу извращения?


 
Pcrepair ©   (2013-01-07 22:24) [33]


> А доступ к индикатору синхронизован? Кто и как обновляет
> его? Откуда уверенность что там верное значение?

синхронизация по КС
там просто обращение к ГП типа ЧИСЛО и отображение значения в ЛЕЙБЛ


> Я спрашиваю в каком состоянии находится соединение, создаваемое
> неким "зависшим" IdHTTP ?
> NetStat что говорит по этому поводу ?

когда узнаю что такое NetStat тогда расскажу
а как можно получит данные о том что происходит в зависшем соединении, когда рассоеденить его можно только отключив программу. при этом выскакивает сообщение об утечке памяти
я тут не просто так узнаю как можно прихлопнуть idhttp


 
Pcrepair ©   (2013-01-07 22:31) [34]

пробовал и само искл от ИНДИ

on E:EIdHTTPProtocolException do
    begin
    ShowMessage(E.ErrorMessage);

но там тоже ничего НЕБЫЛО
точнее были сообщения Reed Timed Out но они к ситуации отношения не имеют, это просто незагруженные страницы


 
Сергей М. ©   (2013-01-07 22:33) [35]


> как можно получит данные о том что происходит в зависшем
> соединении


Средствами той самой стандартной утилиты netstat.
Еще удобней средствами сетевых утилит от Руссиновича.


> я тут не просто так узнаю как можно прихлопнуть idhttp


Тебе же сказали как - закрыв сокет из другого потока.


 
Сергей М. ©   (2013-01-07 22:35) [36]


> точнее были сообщения Reed Timed Out но они к ситуации отношения
> не имеют


Как это не имеют ? Самое прямое отношение они имеют !
Как раз при этом исключении ты и решаешь свою проблему безо всяких "прихлопываний".


 
DVM ©   (2013-01-07 22:36) [37]


> я тут не просто так узнаю как можно прихлопнуть idhttp

Я ж тебе уже 3 раза написал как его прихопнуть. Закрыть евойный сокет из другого потока. Но для этого как минимум надо иметь список потоков работающих.


 
Anatoly Podgoretsky ©   (2013-01-08 00:20) [38]

> Pcrepair  (07.01.2013 22:31:34)  [34]

Тростниковый таймаут?
Что это такое?


 
brother ©   (2013-01-08 08:28) [39]

[34] Формулировка сообщения тайм аута точна?



Страницы: 1 вся ветка

Форум: "Начинающим";
Текущий архив: 2013.09.22;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.59 MB
Время: 0.003 c
10-1178108901
Егоров А.Н.
2007-05-02 16:28
2013.09.22
Excel из Delhpi


2-1357584844
N.Cage
2013-01-07 22:54
2013.09.22
Проблема с QuickReport


15-1365684591
Demo
2013-04-11 16:49
2013.09.22
О веб разработке


1-1314366462
denkop
2011-08-26 17:47
2013.09.22
Как правильно вызвать метод класса из CallBack функции


15-1363286070
Bitt
2013-03-14 22:34
2013.09.22
TImage рисование точки





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский