我们的下载速度存在问题。而且根据方法的不同,它的运行速度可能会快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();
}