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线程)?

c#异步下载速度

有人建议你可以制作一个异步版本的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没有返回任务,所以不能等待。