Xamarin - 多个HTTP请求减慢应用程序的速度

问题描述:

我使用Xamarin开发iOS应用程序。其中一项功能是以hls格式下载视频,这意味着每个视频可以有100到1000个区块下载。所以我需要做100到1000个http请求。这是工作,但下载时应用程序非常慢,我用“乐器”进行了性能测试,CPU处于80%,一旦完成,它会回到0%-1%。这是在iPad上测试,而不是在模拟器上。Xamarin - 多个HTTP请求减慢应用程序的速度

public async Task CreateDownloadTask (string path){ 

var response = await _httpClient.GetAsync (GetUrl(path), 
            HttpCompletionOption.ResponseHeadersRead); 

if (!response.IsSuccessStatusCode) 
{ 
    Debug.WriteLine ("Error: " + path); 
    RaiseFault(new RpcFault("Error: Unable to download video", -1)); 
} 
else 
{ 
    var totalBytes = response.Content.Headers.ContentLength.HasValue 
        ? response.Content.Headers.ContentLength.Value : -1L; 

    using (var stream = await response.Content.ReadAsStreamAsync()) 
    { 
     var isMoreToRead = true; 
     var data = new byte[totalBytes]; 

     do 
     { 
      _cancelSource.Token.ThrowIfCancellationRequested(); 
      var buffer = new byte[4096]; 
      int read = stream.ReadAsync(buffer, 
             0, 
             buffer.Length, 
             _cancelSource.Token).Result; 

      if (read == 0) 
       isMoreToRead = false; 
      else { 
       buffer.ToList().CopyTo (0, data, receivedBytes, read); 
       receivedBytes += read; 
       HlsVideo.TotalReceived += read; 
      } 
     } while(isMoreToRead); 

     var fullPath = GetFullFilePath (path); 
     _fileStore.WriteFile (fullPath, data); 
    } 
} 

如何在做多个http请求时提高性能?

+1

虽然你叫'ToList()'?这是一开始就引入不必要的复制。为什么你要在'while'循环的每次迭代中创建一个新的缓冲区?只需在循环之前创建一次*,以便您可以继续使用相同的缓冲区。事实上,为什么你有'缓冲'呢?你已经有了一个有效的缓冲区 - “数据”。直接读入:'int read = stream.ReadAsync(data,receivedBytes,totalBytes - receivedBytes,_cancelSource.Token).Result;' –

+0

你是对的!我删除了缓冲区,似乎工作得更好。它减少了大约20%的CPU使用率!在物品列表上滚动时仍然不顺畅,因此欢迎提供任何提示。谢谢! – nhenrique

+1

是否有任何理由使用* WriteFile的* synchronous *调用?这可能会使它也生涩...... –

有两种许多问题与当前的代码:

  • 这是低效的读取数据方面
  • 它同步写入的数据,如果你是在UI线程上这显然是一个问题

的“异步写入数据”可能是一个简单的修复,所以让我们看看在读取数据的效率低下:

  • 您在每次迭代中分配buffer。我们不关心前一次迭代的数据,因此您可以在while循环之前分配一次
  • 您在buffer上调用ToList,该副本将生成副本 - 然后将其复制到data
  • 根本不需要buffer!相反,两项拨款,并在每次迭代两个副本的,你可以只读取字节直接data:在你的缓冲

    var data = new byte[totalBytes]; 
    
    do { 
        _cancelSource.Token.ThrowIfCancellationRequested(); 
        int read = stream.ReadAsync(data, receivedBytes, data.Length - receivedBytes, 
               _cancelSource.Token).Result; 
    
        receivedBytes += read; 
        if (read == 0 || receivedBytes == data.Length) 
         isMoreToRead = false; 
        } 
        HlsVideo.TotalReceived += read; 
    } while(isMoreToRead); 
    // TODO: check that receivedBytes == data.Length!