Все мои потоки зависают в HTTPClient.GetAsync(), но из моего приложения никогда не отправляются запросы

Я делаю большое количество запросов API и заметил, что иногда приложение "зависает" в HTTPClient.GetAsync(). У меня есть очередь запросов, и каждый раз, когда делается запрос, он выполняет для него задачу, поэтому он может быстро перейти к следующему и не ждать его возврата.

Почти случайно потоки начнут накапливаться, пока я не достигну своего предела пула потоков. Они все накапливаются на HttpResponseMessage response = client.GetAsync(BaseUrl + endpoint + ToQueryString(request)).Result;, Если я устанавливаю тайм-аут на HTTPClient, он никогда не истекает. Используя монитор сети Microsoft, я смог определить, что ни один из запросов на самом деле не отправляется, когда это происходит.

Это не является надежно воспроизводимым. Я могу выполнить 100 запросов или 10000 запросов до того, как это начнется.

Оскорбительный код:

private T Get<T>(string endpoint, IRequest request) where T : class
    {
        return Get2<T>(endpoint, request).Result;
    }

    private async Task<T> Get2<T>(string endpoint, IRequest request) where T : class
    {
        var client = InitHttpClient();

        string debug = BaseUrl + endpoint + ToQueryString(request);
        HttpResponseMessage response = await client.GetAsync(BaseUrl + endpoint + ToQueryString(request)).ConfigureAwait(false);
        //HttpResponseMessage response = client.GetAsync(BaseUrl + endpoint + ToQueryString(request)).Result;
        string body = response.Content.ReadAsStringAsync().Result;

        if (response.IsSuccessStatusCode)
        {
            T result = JsonConvert.DeserializeObject<T>(body, _serializerSettings);

            return result;
        }

        var error = JsonConvert.DeserializeObject<HelpScoutError>(body);
        throw new HelpScoutApiException(error, body);
    }

Примечание: после прочтения этого: http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html я переключил свой код на то, что вы видите выше в качестве теста. Теперь темы застряли на: return Get2<T>(endpoint, request).Result;

Изменить: код перед его изменением:

        private async <T> Get<T>(string endpoint, IRequest request) where T : class
    {
        var client = InitHttpClient();

        string debug = BaseUrl + endpoint + ToQueryString(request);
        HttpResponseMessage response = client.GetAsync(BaseUrl + endpoint + ToQueryString(request)).Result;
        string body = response.Content.ReadAsStringAsync().Result;

        if (response.IsSuccessStatusCode)
        {
            T result = JsonConvert.DeserializeObject<T>(body, _serializerSettings);

            return result;
        }

        var error = JsonConvert.DeserializeObject<HelpScoutError>(body);
        throw new HelpScoutApiException(error, body);
    }

Что я могу сделать, чтобы отладить это? Любое понимание того, что может быть причиной этого?

Edit2: После некоторого дополнительного поиска, это могло быть вызвано каким-то тупиком? Я делаю новый HTTPClient для каждого запроса (что, как я понимаю, немного плохо), поэтому я подумал, что это не произойдет.

Edit3: это клиент API, в котором я работаю, любой из Get методы приводят к коду, о котором я написал. https://github.com/Selz/HelpScoutNet/blob/master/src/HelpScoutClient.cs

1 ответ

Ответ на этот вопрос заключается в том, что это, скорее всего, проблема взаимоблокировки.

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

Я исправил это, создав асинхронный клиент для этой библиотеки, гарантируя, что методы anyc используются во всем стеке вызовов. После использования полностью асинхронной совместимой библиотеки проблема исчезла.

Другие вопросы по тегам