0

Есть задача - асинхронно распарсить данные, get запросов очень много, поэтому решил распараллелить вот таким образом.

await Task.Run(() =>
{
    Parallel.ForEach(collection, (itemFrom) =>
    {
        foreach (var itemTo in collection)
        {
            List<ResponseModel> result = default;
            try
            {
                result = (List<ResponseModel>)ParseByCurrencyAsync(itemFrom.Key, itemTo.Key).Result;
            }
            catch (Exception ex){ }
        }
    });
});

В результате получаю ошибку из заголовка темы, ну и вот это дело code

Почитал информацию по данной ошибке, судя по всему истекает время ожидания ответа. Видимо очень много запросов и сервер их блокирует. Подскажите пожалуйста, есть ли какое то решение для данной задачи?

  • Исходный код принято размещать в виде текста. – Protect children of Donbas2014 Jun 22 '22 at 05:54
  • Извиняюсь, поправил – Alex Stalker Jun 22 '22 at 06:39
  • А разве не нужно делать await ParseByCurrencyAsync? – CrazyElf Jun 22 '22 at 07:15
  • а я там свойство Result вызываю, оно же вроде эквивалентно ожиданию...или нет? – Alex Stalker Jun 22 '22 at 07:17
  • Ну вы попробуйте. По-моему результат можно смотреть только когда он уже готов. – CrazyElf Jun 22 '22 at 07:27
  • В документации написано "Доступ к методу доступа к свойству блокирует вызывающий поток до завершения асинхронной операции; Он эквивалентен вызову Wait метода." Я так понял, что Result ждёт. Попробую конечно await, но обычно раньше Result всегда хватало... – Alex Stalker Jun 22 '22 at 07:50
  • 1
    А, ну да, наверное. Просто нерационально ждёт, не отпуская поток, а так, наверное, можно. Ну тогда саму функцию ParseByCurrencyAsync надо разбирать. Если вас блокирует сервер - ну, пробуйте менять хедеры, а то и ip надо менять, прокси ротировать. Простые методы вряд ли есть. – CrazyElf Jun 22 '22 at 07:53
  • похоже, что да... единственное... я думал может ещё как то попробовать время ожидания ответа увеличить – Alex Stalker Jun 22 '22 at 07:54
  • Нужно подробнее ошибку как-то посмотреть, сейчас это краткое какое-то описание. – CrazyElf Jun 22 '22 at 07:59
  • 1
    да, похоже я перебрал с запросами) сервак включил ддос защиту – Alex Stalker Jun 22 '22 at 08:09

1 Answers1

3

Исключение возвращает метод ParseByCurrencyAsync, и показанный код здесь не при чем. Но это плохой код, технически и семантически. Вот хороший эквивалент:

var tasks = new List<Task<List<ResponseModel>>>();
foreach (var itemTo in collection)
{
    tasks.Add(ParseByCurrencyAsync(itemFrom.Key, itemTo.Key));
}
List<ResponseModel>[] result = await Task.WhenAll(tasks);

Но я на вашем месте бы задумался над ограничением количества одновременно работающих запросов


Никогда не используйте .Result, его можно использовать только для завершенных задач, например пусть будет некий task типа Task<int>:

// ВОТ ТАК НЕЛЬЗЯ
int number = task.Result;

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

Другой пример

// вот так можно
await task;
int number = task.Result;

А проще

int number = await task;

Как видите, практической пользы от .Result никакой, но она иногда есть, вот рабочий пример, где я не знаю, синхронно завершился вызванный метод или асинхронно (да, такое тоже бывает):

if (!task.IsCompleted)
{
    await task;
}
int number = task.Result;

Что-то вроде оптимизации, запускаю ожидание только если нужно. Но случай действительно редкий и большинство разработчиков, чтобы не путатья сделают проще int number = await task;, и я вам тоже советую использовать только await, и никак иначе.

aepot
  • 49,560