Как оптимизировать этот код и вызывать API каждые 40 мс

Я хочу опросить один датчик, который возвращает ответ JSON Rest Api. Я вызываю API каждые 40 миллисекунд, но это выдает мне эту ошибку:

в System.Threading.Tasks.Task1.GetResultCore (логическое ожиданиеCompletionNotification) в System.Threading.Tasks.Task1.get_Result()

У меня есть таймер, где interval = 40. И это код, как я вызываю Api:

 private void Timer(object sender, EventArgs e)
        {
            tmrPollingSick.Stop();

            string strJson = "";
           
            HttpClient client = new HttpClient();
            string baseUrl = "http://9999.99999.99999.8";
            client.BaseAddress = new Uri(baseUrl);
            var contentType = new MediaTypeWithQualityHeaderValue("application/json");
            client.DefaultRequestHeaders.Accept.Add(contentType);
            string strAltezza = string.Empty;
            try
            {
                strJson = "Here I set HEADERS... DATA ect " + Convert.ToChar(34) +
                        "header" + Convert.ToChar(34) + ": {............" 

                var contentData = new StringContent(strJson, System.Text.Encoding.UTF8, "application/json");
                using (var responseMessage = client.PostAsync("/bla/bla/bla", contentData).Result)
                {
                    if (responseMessage.IsSuccessStatusCode)
                    {
                        string strContext = responseMessage.Content.ReadAsStringAsync().Result;

                        Object dec = JsonConvert.DeserializeObject(strContext);     // deserializing Json string (it will deserialize Json string)

                        JObject obj = JObject.Parse(strContext);
                        //Process Data In
                        JObject obj1 = JObject.Parse(obj["bla"].ToString());
                        JObject obj2 = JObject.Parse(obj1["processDataIn"].ToString());
                        strAltezza = obj2["1"].ToString();
                        textBox1.Text = strAltezza;

                    }
                }
            }

        catch(WebException ex1)
        {
            MessageBox.Show("web: "+ex1.StackTrace.ToString() + " - " + ex1.Message);
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.StackTrace.ToString() + " - " + ex.Message);
        }
        tmrPollingSick.Start();
    }

Все работает нормально, но через некоторое время выдает эту ошибку. Я уже прочитал это (Как реализовать данные в реальном времени для веб-страница и это), но я их еще не пробовал. Любые предложения, как это исправить? Есть ли другой способ, как получить результат в реальном времени без сбоев?


person kvacka    schedule 01.10.2020    source источник
comment
Зарегистрируйтесь и опубликуйте полный. исключения, а не только его части. То, что вы опубликовали, содержит только 2 строки из трассировки стека. Использование .Result определенно неправильно, но сейчас невозможно догадаться, что на самом деле не так. Вы достигли предела регулирования сервера? Создание нового HttpClient вместо повторного использования одного и того же экземпляра привело к исчерпанию сокетов? Какая-то другая проблема?   -  person Panagiotis Kanavos    schedule 01.10.2020
comment
Кстати, после того, как вы проанализируете строку JSON, нет смысла снова анализировать ее элементы. Однако в вашем коде вы используете как JsonConvert , так и JObject.Parse, таким образом дважды анализируя один и тот же ответ.   -  person Panagiotis Kanavos    schedule 01.10.2020
comment
Http не лучший выбор для этого, он каждый раз создает соединение и плюс все накладные расходы... вместо этого вам следует рассмотреть возможность использования SignalR или чего-то подобного.   -  person Patrick Beynio    schedule 01.10.2020
comment
@PatrickBeynio вместо Http, что еще я могу использовать?   -  person kvacka    schedule 02.10.2020


Ответы (2)


Могу ли я назвать это упрямым объединением?

  1. Вы не хотите использовать таймер. То, что вы хотите, это x времени между циклами запроса-ответа. (Это решит исчерпание сокета).
  2. Разделите свой код на этапы (инициализация клиента, выборка запроса, обработка ответа). См. ответ @Oliver.
  3. Создайте функцию для выполнения всего. И запустите своего рода бесконечный цикл foreach, в котором вы можете спать в течение x времени после вызова функции выборки (и процесса, но вы можете отложить это до другого потока или сделать это асинхронно).
person Pedro Rodrigues    schedule 02.10.2020

Когда вы вызываете этот метод все 40 мс, у вас заканчиваются сокеты отправки, потому что вы каждый раз создаете новый файл HttpClient. Даже помещение этого в оператор using (поскольку HttpClient реализует IDisposable) не решит эту проблему, потому что базовый сокет будет заблокирован на 3 минуты от ОС (взгляните на этот ответ для дальнейших объяснений).

Вы должны разделить этот материал на некоторую фазу инициализации, где вы настраиваете клиент, формируете запрос, насколько это возможно, и в этом методе таймера просто вызываете метод PostAsync() и проверяете ответ.

person Oliver    schedule 01.10.2020
comment
Я поместил его в using и больше не выдает эту ошибку. Но время отклика составляет 200 мс. не знаю как оптимизировать - person kvacka; 02.10.2020