如何提高HttpContent.ReadAsStreamAsync()

时间:2019-07-15 09:32:12

标签: c# xamarin xamarin.forms download httpclient

我们的下载速度存在问题。而且根据方法的不同,它的运行速度可能会快20倍。

慢速方法是HttpContent.ReadAsStreamAsync()。我们使用这种方法,以便我们可以逐步进行下载。 我尝试使用HttpContent.ReadAsByteArrayAsync(),这快得多了!!

正常吗? 如何提高ReadAsStreamAsync的下载速度? 它试图扩大缓冲区的大小,但没有改变任何东西...

奇怪的是:在模拟器上运行时,ReadAsStreamAsync速度似乎还可以。

下面两个测试的简化代码

慢速方法:

int bufferSizeHttp = 1024 * 4;
using (Stream stream = await response.Content.ReadAsStreamAsync())
{                
    do
    {
        var percentBefore = percent;                    
        try
        {   
            var bytesRead = await stream.ReadAsync(buffer, 0, bufferSizeHttp);

            if (bytesRead > 0)
            {
                var data = new byte[bytesRead];
                buffer.ToList().CopyTo(0, data, 0, bytesRead);
                await saveFileStream.WriteAsync(data, 0, data.Length);
                await saveFileStream.FlushAsync();

                totalBytesRead += bytesRead;
                percent = Math.Floor((double)(totalBytesRead * 100 / totalBytes));
            }

            //other stuff
    }
}

快速方法:

var data = await response.Content.ReadAsByteArrayAsync();
do
{                    
    var percentBefore = percent;                    
    try
    {
        var bytesRead = data.Length;

        if (bytesRead > 0)
        {
            await saveFileStream.WriteAsync(data, 0, bytesRead);
            await saveFileStream.FlushAsync();

            totalBytesRead += bytesRead;
            percent = Math.Floor((double)(totalBytesRead * 100 / totalBytes));
        }

        //other stuff
    }
}

-编辑-

这是我的测试结果。

每次我下载相同的文件。这是一个54Mo文件。

首次测试:实际方法:

var bytesRead = await stream.ReadAsync(buffer, 0, bufferSizeHttp);
                        if (bytesRead > 0)
                        {
                            var data = new byte[bytesRead];
                            buffer.ToList().CopyTo(0, data, 0, bytesRead);
                            await saveFileStream.WriteAsync(data, 0, data.Length);
                            await saveFileStream.FlushAsync();

                            totalBytesRead += bytesRead;
                            percent = Math.Floor((double)(totalBytesRead * 100 / totalBytes));
                        }

结果:7分12秒


第二项测试:直接将buffer写到WriteAsync。然后最后冲洗一次

var bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);

                if (bytesRead > 0)
                {
                    await saveFileStream.WriteAsync(buffer, 0, bytesRead);

                    totalBytesRead += bytesRead;
                    percent = Math.Floor((double)(totalBytesRead * 100 / totalBytes));
                }

结果:6分10秒


第三项测试:使用Write代替WriteAsync

var bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);

                        if (bytesRead > 0)
                        {
                            saveFileStream.Write(buffer, 0, bytesRead);

                            totalBytesRead += bytesRead;
                            percent = Math.Floor((double)(totalBytesRead * 100 / totalBytes));
                        }

结果:2分20秒。 这似乎是最好的改进,但是我不确定使用Write而不是WriteAsync会遇到的风险。


第四次测试:使用ReadAsByteArrayAsync代替ReadAsStreamAsync

        var data = await response.Content.ReadAsByteArrayAsync();
        do
        {
            var percentBefore = percent;
            try
            {
                var bytesRead = data.Length;// await stream.ReadAsync(buffer, 0, buffer.Length);

                if (bytesRead > 0)
                {
                    //var data = new byte[bytesRead];
                    //buffer.ToList().CopyTo(0, data, 0, bytesRead);
                    await saveFileStream.WriteAsync(data, 0, bytesRead);//data.Length);
                   // await saveFileStream.FlushAsync();

                    totalBytesRead += bytesRead;
                    percent = Math.Floor((double)(totalBytesRead * 100 / totalBytes));
                }

结果:29秒。


完整功能

private async Task DownloadFileAsync(string url, string pathFileLocal)
        {           
            long iExistLen = 0;
            FileStream saveFileStream = null;

            if (File.Exists(pathFileLocal))
            {
                FileInfo fINfo = new FileInfo(pathFileLocal);
                iExistLen = fINfo.Length;
            }

            //On fait du resuming (on demande au serveur de nous envoyer que ce que l'on a pas déjà)
            client.DefaultRequestHeaders.Range = new RangeHeaderValue(iExistLen,null);               
            var buffer = new byte[bufferSizeHttp];            
            HttpResponseMessage response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);//, cancellationToken

            if (!response.IsSuccessStatusCode)
            {
                CTnet.logger.Trace("HttpRequest::DownloadFileAsync : Erreur HTTP " + response.StatusCode + " sur l'url " + url);
                throw new Exception("Erreur de Synchronisation !");
            }
            response.EnsureSuccessStatusCode();

            if (iExistLen > 0)
                saveFileStream = new FileStream(pathFileLocal, FileMode.Append, FileAccess.Write);
            else
                saveFileStream = new FileStream(pathFileLocal, FileMode.Create, FileAccess.Write);

            var totalBytes = response.Content.Headers.ContentLength + iExistLen;
            long totalBytesRead = iExistLen;
            double percent = 0;
            if (totalBytes > 0)
            {
                percent = Math.Floor((double)(totalBytesRead * 100 / totalBytes));
            }

            try
            {
                DownloadProgressChanged?.Invoke(totalBytes, totalBytesRead, percent);
            }
            catch (Exception ex)
            {
                CTnet.logger.Trace("HttpRequest::DownloadFileAsync : Erreur dans la fonction gérant la progression du téléchargement, raison : " + ex.Message);
            }

            CTnet.logger.Trace("HttpRequest::DownloadFileAsync : Lancement du téléchargement du fichier " + url);
            using (Stream stream = await response.Content.ReadAsStreamAsync())
            {                
                do
                {                    
                    var percentBefore = percent;                    
                    try
                    {   
                        var bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);

                        if (bytesRead > 0)
                        {
                            saveFileStream.Write(buffer, 0, bytesRead);

                            totalBytesRead += bytesRead;
                            percent = Math.Floor((double)(totalBytesRead * 100 / totalBytes));
                        }
                        else
                        {
                            if (totalBytesRead == totalBytes)
                            {
                                percent = 100;
                            }
                            else
                            {
                                CTnet.logger.Trace("HttpRequest::DownloadFileAsync : Probleme de téléchargement du fichier " + url + ", " + totalBytesRead + " octets téléchargés sur " + totalBytes + "(" + percent + "%)");
                                if (File.Exists(pathFileLocal))
                                {
                                    File.Delete(pathFileLocal);
                                }                                
                                throw new Exception("Erreur de Synchronisation !");
                            }
                        }

                        if (percent > percentBefore)
                        {
                            try
                            {
                                DownloadProgressChanged?.Invoke(totalBytes, totalBytesRead, percent);
                            }
                            catch (Exception ex)
                            {
                                CTnet.logger.Trace("HttpRequest::DownloadFileAsync : Erreur dans la fonction gérant la progression du téléchargement, raison : " + ex.Message);
                            }                           
                        }
                    }
                    catch (Exception)
                    {
                        saveFileStream.Close();
                        throw;
                    }
                }
                while ((totalBytesRead < totalBytes) && (!cancellationToken.IsCancellationRequested));
            }

            await saveFileStream.FlushAsync();
            saveFileStream.Close();           
        }

0 个答案:

没有答案