c#异步下载速度
本文关键字:下载速度 异步 | 更新日期: 2023-09-27 18:07:58
我正在尝试获取当前用户的网络下载速度。在使用NetworkInterfaces等工具时遇到了死胡同之后,我尝试了一个在网上找到的解决方案。我编辑了一下,它工作得很好,但它不是异步的。
public static void GetDownloadSpeed(this Label lbl)
{
double[] speeds = new double[5];
for (int i = 0; i < 5; i++)
{
int fileSize = 407; //Size of File in KB.
WebClient client = new WebClient();
DateTime startTime = DateTime.Now;
if (!Directory.Exists($"{CurrentDir}/tmp/speedtest"))
Directory.CreateDirectory($"{CurrentDir}/tmp/speedtest");
client.DownloadFile(new Uri("https://ajax.googleapis.com/ajax/libs/threejs/r69/three.min.js"), "/tmp/speedtest/three.min.js");
DateTime endTime = DateTime.Now;
speeds[i] = Math.Round((fileSize / (endTime - startTime).TotalSeconds));
}
lbl.Text = string.Format("{0}KB/s", speeds.Average());
}
该函数在计时器内每隔2分钟调用一次。
MyLbl.GetDownloadSpeed()
我试过使用WebClient。DownloadFileAsync,但这只是显示了无限制符号。我的下一个尝试是使用HttpClient,但在我继续之前,有没有人有一个建议的方法来获得当前用户异步下载速度(不滞后主GUI线程)?
有人建议你可以制作一个异步版本的GetDownloadSpeed()
:
async void GetDownloadSpeedAsync(this Label lbl, Uri address, int numberOfTests)
{
string directoryName = @"C:'Work'Test'speedTest";
string fileName = "tmp.dat";
if (!Directory.Exists(directoryName))
Directory.CreateDirectory(directoryName);
Stopwatch timer = new Stopwatch();
timer.Start();
for (int i = 0; i < numberOfTests; ++i)
{
using (WebClient client = new WebClient())
{
await client.DownloadFileTaskAsync(address, Path.Combine(directoryName, fileName), CancellationToken.None);
}
}
lbl.Text == Convert.ToString(timer.Elapsed.TotalSeconds / numberOfTests);
}
WebClient类相对较老,没有可等待 DownloadFileAsync()
。
正如正确指出的那样,WebClient实际上有一个基于任务的async方法DownloadFileTaskAsync(),我建议使用。下面的代码仍然可以帮助解决没有提供返回Task
的异步方法的情况。
我们可以在TaskCompletionSource<T>
的帮助下修复它:
public static class WebClientExtensions
{
public static Task DownloadFileAwaitableAsync(this WebClient instance, Uri address,
string fileName, CancellationToken cancellationToken)
{
TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
// Subscribe for completion event
instance.DownloadFileCompleted += instance_DownloadFileCompleted;
// Setup cancellation
var cancellationRegistration = cancellationToken.CanBeCanceled ? (IDisposable)cancellationToken.Register(() => { instance.CancelAsync(); }) : null;
// Initiate asyncronous download
instance.DownloadFileAsync(address, fileName, Tuple.Create(tcs, cancellationRegistration));
return tcs.Task;
}
static void instance_DownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
((WebClient)sender).DownloadDataCompleted -= instance_DownloadFileCompleted;
var data = (Tuple<TaskCompletionSource<object>, IDisposable>)e.UserState;
if (data.Item2 != null) data.Item2.Dispose();
var tcs = data.Item1;
if (e.Cancelled)
{
tcs.TrySetCanceled();
}
else if (e.Error != null)
{
tcs.TrySetException(e.Error);
}
else
{
tcs.TrySetResult(null);
}
}
}
等待Task.Run尝试" (()=> {//代码});
编辑:@JustDevInc我仍然认为你应该使用DownloadAsync。Task.Run(delegate)创建一个新线程,你可能想要避免它。如果你愿意,可以把你的旧代码贴出来,这样我们可以试着修复它。编辑:第一个解决方案被证明是两个解决方案中唯一有效的。DownloadFileAsync没有返回任务,所以不能等待。