Ожидание завершения всех асинхронных вызовов WebClient - PullRequest
0 голосов
/ 09 марта 2012

Я использую класс WebClient в C #, 4.0.Мне нужно подключиться к службе REST с 30 000 различных идентификаторов и получить результат статуса (200 или 404).Вот метод, который делает вызовы (eventCounter является объектом CountdownEvent):

private void doWork()
    {
        initDB();
        List<string> _lines = new List<string>();
        //pull all UpcIds into a List
        using (StreamReader _rdr = new StreamReader(@"C:\Users\kkohut\Dropbox\ROVI\Application Support\BestBuy\upc_test2.txt"))
        {
            string _line;
            while ((_line = _rdr.ReadLine()) != null)
            {
                _lines.Add(_line);
            }
        }

        numIds = _lines.Count();

        for (int i = 0; i < numIds; i++)
        {
            string _upcId = _lines[i];
            WebClient c = new WebClient();
            c.DownloadDataCompleted += new DownloadDataCompletedEventHandler(c_DownloadDataCompleted);
            c.DownloadDataAsync(new Uri(BASE_URL + _upcId), _upcId);
        }
        //this is not working correctly. Code execution hits this line and waits, without processing any of the 
        //the DownloadDataCompleted eventhandlers
        eventCounter.Wait();
    }

Вот обработчик события DownloadDataCompleted

void c_DownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e)
    {
        DataSet _ds = new DataSet();
        string _upcId = e.UserState.ToString();
        string _status = "404";
        try
        {
            if (!e.Cancelled && e.Error == null)
            {
                string _result = System.Text.Encoding.UTF8.GetString(e.Result);
                if (_result.IndexOf("<code>200</code>") > 0)
                {
                    _status = "200";
                }
            }
        }
        catch (Exception ex)
        {
            _status = "404";
        }
        finally
        {
            updateDB(_upcId, _status);
            eventCounter.Signal(1);
            txtLog.Text += string.Format("{0}\t{1}\t{2}\r\n",ctr, _upcId, _status);
        }
    }

Если я закомментирую eventCounter.Wait ()Скажите, звонки работают, но я не знаю, когда они завершатся.Это приложение winforms, так что пока я поддерживаю форму, все вызовы завершены.Но если я раскомментирую инструкцию eventCounter.Wait (), никакие вызовы не обрабатываются.Похоже, что оператор Wait () блокирует асинхронные вызовы для начала.Каждый найденный мной пример использует этот подход, но ни один из них не сигнализирует о CountdownEvent в обработчике завершенного события.Мысли?

1 Ответ

2 голосов
/ 09 марта 2012

Класс WebClient реализует Асинхронный шаблон на основе событий (EAP) .

В этом шаблоне метод XXXAsync захватывает текущий SynchronizationContext (то есть поток пользовательского интерфейса в приложении WPF или WinForms). Когда операция завершается, в этом контексте выполняется обработчик события.

(См. Также: В каком потоке (ах) WebClient генерирует свои события? )

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

Решение: Асинхронно дождитесь завершения CountdownEvent , а не синхронно.

Вы можете использовать ThreadPool.RegisterWaitForSingleObject Method , чтобы зарегистрировать обратный вызов для WaitHandle CountdownEvent .

...