Веб-запрос неожиданно перестает работать - PullRequest
2 голосов
/ 19 февраля 2010
HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(baseurl + url);
req.Timeout = 1000 * 10;
HttpWebResponse response = (HttpWebResponse)req.GetResponse();
Stream str = response.GetResponseStream();
HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
doc.Load(str);
response.Close();
string imgurl = doc.DocumentNode.SelectSingleNode("//div[@class='one-page']/a/img[@class='manga-page']").Attributes["src"].Value;
req = (HttpWebRequest)HttpWebRequest.Create(imgurl);
req.Timeout = 1000 * 10;
response = (HttpWebResponse)req.GetResponse();
str = response.GetResponseStream();
Image img = Image.FromStream(str);
response.Close();
return img;

Я запускаю этот код в цикле (используя несколько потоков), чтобы загрузить около 4000 изображений, и он отлично работает в течение первых сотен, но затем (в разное время для каждого раза, когда я пытаюсь) он внезапно перестает работать, и каждый вызов «req.GetResponse ()» приводит к исключению TimeoutException. Я понятия не имею, почему это происходит, и не знаю, что может быть не так или как с этим бороться. Любая помощь будет принята с благодарностью.

Код, который я использую для запуска этой функции (она называется GetPage (int) и называется c.GetPage (t)), выглядит следующим образом:

for (int j = 0; j < 2; j++)
{
    BackgroundWorker bw = new BackgroundWorker();
    num[bw] = j;
    bgs.Add(bw);
    bw.DoWork += (object sender, DoWorkEventArgs doargs) =>
    {
        int t = -1;
        lock (lockObjForQueueOperations)
        {
            if (images.Count != 0)
                t = images.Dequeue();
        }
        if(t < 0)
        {
            doargs.Result = false;
            return;
        }
        currently[sender] = t;
        Image img;
        try { img = c.GetPage(t); }
        catch (Exception e)
        {
            lock (lockObjForQueueOperations)
            {
                images.Enqueue(t);
            }
            lock (Console.Title)
            {
                if (num[sender] == 0) Console.ForegroundColor = ConsoleColor.Cyan;
                else if (num[sender] == 1) Console.ForegroundColor = ConsoleColor.Yellow;
                Console.WriteLine("**ERR: Error fetshing page {0}, errormsg: {1}", t, e.Message);
                Console.ForegroundColor = ConsoleColor.White;
            }
            doargs.Result = true;
            Thread.Sleep(1000*2);
            return;
        }
        lock (Console.Title)
        {
            if (num[sender] == 0) Console.ForegroundColor = ConsoleColor.Cyan;
            else if (num[sender] == 1) Console.ForegroundColor = ConsoleColor.Yellow;
            Console.WriteLine("\t\tLoaded page {0} of {1}.", t + 1, c.PagesCount);
            Console.ForegroundColor = ConsoleColor.White;
        }
        string imgpath = Path.Combine(ndir, "Page " + (t + 1) + ".png");
        img.Save(imgpath, System.Drawing.Imaging.ImageFormat.Png);
        img.Dispose();
        doargs.Result = true;
    };
    bw.RunWorkerCompleted += (object sender, RunWorkerCompletedEventArgs runargs) =>
    {
        if ((bool)runargs.Result) bw.RunWorkerAsync();
        else
        {
            finnishedworkers++;
            if (finnishedworkers == 2) restetter.Set();
            bw.Dispose();
        }
    };
    bw.RunWorkerAsync();
}

Ответы [ 2 ]

2 голосов
/ 19 февраля 2010

У вас плохой дизайн. Вместо создания потоков для каждого запроса попробуйте вызвать BeginGetResponse. Фреймворк будет обрабатывать выделение потоков из пула потоков для обслуживания ваших запросов.

Добавить вызов в ServicePointManager.SetDefaultConnectionLimit (?), Не уверенный в этом, к числу, подобному 100.

создать семафор со счетчиком, совпадающим с ограничением числа подключений.

В вашей функции, которая вызывает BeginGetResponse, добавьте вызов semaphore.WaitOne () как раз перед тем, как ваш вызов получит BeginGet ...

В обработчике EndGetResponse () вызовите semaphore.Release (), чтобы продолжить следующий запрос.

Вы, вероятно, исчерпываете пул потоков со всеми своими собственными потоками. Контролируйте свой процесс и посмотрите, не можете ли вы выполнить его и использовать всего 5-10 потоков. Возможно, вы можете войти в Thread.Current.ThreadID, чтобы увидеть, как один и тот же поток обрабатывает несколько запросов.

Сделано это миллиарды раз. На самом деле.

2 голосов
/ 19 февраля 2010

Свойство Timeout в HttpWebRequest указывается в миллисекундах. В настоящее время его установка на 10 000 составляет всего 10 секунд, и этого может быть недостаточно, исходя из пропускной способности и размера извлекаемых данных, а также сложности выполняемого кода. Я говорю, попробуйте сначала увеличить это.

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