Десериализация Blazor WebAssembly намного медленнее, чем даже загрузка? Что случилось? - PullRequest
2 голосов
/ 04 августа 2020

В моем приложении Blazor у меня есть компонент с таким методом. (Я заменил вызов GetFromJsonAsyn c кодом изнутри, чтобы сократить медленную часть.)

  private async Task GetData()
  {
      IsLoading = true;
      string url = $".../api/v1/Foo";  // will return a 1.5 MB JSON array
      var client = clientFactory.CreateClient("MyNamedClient");

      Console.WriteLine($"starting");

      List<Foo> results;

      Task<HttpResponseMessage> taskResponse = client.GetAsync(url, HttpCompletionOption.ResponseContentRead, default);

      var sw = Stopwatch.StartNew();
      using (HttpResponseMessage response = await taskResponse)
      {
        
        response.EnsureSuccessStatusCode();
        var content = response.Content!;

        if (content == null)
        {
          throw new ArgumentNullException(nameof(content));
        }
        
        string contentString = await content.ReadAsStringAsync();

        sw.Stop();
        Console.WriteLine($"Read string: {sw.Elapsed}");
        sw.Restart();

        results = System.Text.Json.JsonSerializer.Deserialize<List<Foo>>(contentString);

      }

      sw.Stop();
      Console.WriteLine($"Deserialize: {sw.Elapsed}");
      
      StateHasChanged();
      IsLoading = false;

Моя загрузка 1,5 МБ занимает 1-6 секунд, но остальная часть операции (во время которого пользовательский интерфейс заблокирован) занимает 10-30 секунд. Это просто медленная десериализация в ReadFromJsonAsync (которая вызывает System.Text.Json.JsonSerializer.Deserialize внутри), или здесь происходит что-то еще ? Как я могу повысить эффективность получения этого большого набора данных (хотя он не такой уж и большой, я думаю!)

Я закомментировал все, что связано с Results Упростите, и вместо этого у меня просто есть индикатор, привязанный к IsLoading. Это говорит о том, что нет проблем с обновлением DOM или рендерингом.

Когда я пробую тот же набор кода в автоматическом интеграционном тесте, это занимает всего 3 секунды или около того. Действительно ли WebAssembly так медленно выполняет десериализацию? Если да, то является ли единственное решение извлекать очень маленькие наборы данных повсюду на моем сайте? Мне это кажется неправильным.

Вот итоговый журнал консоли браузера при выполнении вышеуказанного кода:

VM1131:1 Fetch finished loading: GET "https://localhost:5001/api/v1/Foo".
read string 00:00:05.5464300
Deserialize: 00:00:15.4109950
L: GC_MAJOR_SWEEP: major size: 3232K in use: 28547K
L: GC_MAJOR: (LOS overflow) time 18.49ms, stw 18.50ms los size: 2048K in use: 187K
L: GC_MINOR: (LOS overflow) time 0.33ms, stw 0.37ms promoted 0K major size: 3232K in use: 2014K los size: 2048K in use: 187K

Что бы это ни стоило, вот график производительности Chrome. Зеленый цвет - загрузка, а оранжевый - «выполнение микрозадач», что, как я полагаю, означает работу WebAssembly.

введите описание изображения здесь

1 Ответ

1 голос
/ 06 августа 2020

или здесь что-то еще происходит?

Похоже так. Вы не указали, какое оборудование вы используете, но на моем рабочем столе (i7) я могу загрузить менее 100 мс (локальный хост), а десериализация занимает менее 4 секунд. Нет большой разницы между режимами отладки и выпуска или между браузерами.

Итак, 5 секунд для простой загрузки с localhost уже очень странно. Что-то не так в вашей настройке.

MCVE:

  • Начните с шаблона Wasm Hosted
  • Сделайте так, чтобы контроллер возвращал ~ 17000 элементов (было 5), чтобы получить ~ 1,5 МБ
  • Поместите свой код в FetchData OnInit (), замените Foo на WeatherForecast
  • Не пытайтесь визуализировать их все.

Посмотрите, какие результаты вы получите за это.

...