C#在使用多个线程进行dowloading时正确计算下载速度



我试图向用户显示正确的下载速度,但我的应用程序下载同时是一堆小文件,为了加快速度,我使用了Parallel.ForEach。然而,我无法计算正确的下载速度。根据我当前的代码,我基本上是在计算平均下载速度,而不是当前的下载速度。因为它在每次下载完成时都会更新UI。当我使用普通的foreach时,我可以正确地计算,但速度很慢。如何使用多个线程和多个文件正确显示下载的Mbps?

注意:这个应用程序是WPF,但我几乎没有使用任何MVVM。这是我第一次使用WPF,现在我只是想做一个外观好看、功能良好的东西。

下载功能

var stopwatch = new Stopwatch();
stopwatch.Start();
DownloadController.stopwatch.Start();
DownloadController.IsDownloadStarted = true;
DownloadController.IsDownloadInProgress = true;
Parallel.ForEach(downloadList, new ParallelOptions { MaxDegreeOfParallelism = 5 }, file =>
{
try
{
DownloadController.LastDownloadingFileName = file.FileName;
GET_DownloadFile(file.FileName, file.LastUpdate.UnixTimeStampToDateTime()).GetAwaiter().GetResult();
logger.Info("Download", file.FileName, "Downloading file completed");
}
catch (Exception ex)
{
lock (_failedDownloads)
{
_failedDownloads.Add(file);
}
logger.Exception(ex, "Download", file.FileName, file.LastUpdate, file.Size, $"Failed to download file");
}
});

进度更改事件

public static void DownloadProgressChangedEvent(object sender, DownloadProgressChangedEventArgs e)
{
MainWindow._dispatcher.BeginInvoke(new Action(() =>
{
ButtonProgressAssist.SetValue(MainWindow.This.Prog_Downloading, ProgressValue);
ButtonController.ButtonPlay_Downloading();
if (e.ProgressPercentage == 100)
{
DownloadedSize += e.TotalBytesToReceive;
var downloadSpeed = string.Format("{0} ", (DownloadedSize / 1024.0 / 1024.0 / stopwatch.Elapsed.TotalSeconds).ToString("0.0"));
var text1 = $"({ProgressValue}% - {DownloadedFileCount}/{TotalFileUpdateCount}) @ {downloadSpeed}MB/s {EasFile.GetFileNameWithExtension(LastDownloadingFileName)} ";
MainWindow.This.DownloadTextBlock.Text = text1;
}
}));
}

ProgressCompletedEvent

public static void DownloadProgressCompletedEvent(object? sender, AsyncCompletedEventArgs e)
{
if (!e.Cancelled)
{
DownloadedFileCount++;
}
}

我尝试使用PerformanceCounter来查看我当前应用程序的网络使用情况,但它只显示特定网络上所有使用情况的使用情况。

您有两个选择:第一种方法是创建一个类来处理单个文件的下载。在这个类中,您应该计算下载的字节数。一个可能的解决方案是拥有一个每秒被清除的成员。应该将接收到的字节添加到其中。在清除之前,类应该将该值报告给它应该是成员的主类,对所有当前下载的文件采取相同的方式。另一种解决方案是不在每个进度事件上都有一个类来报告接收到的字节和时间。在主类中,应该有一个列表来存储这些对。然后,每隔一秒,您只能获得最后一秒的记录,并聚合接收到的字节。

p.S.访问成员应该是线程安全的。

最新更新