C#异步下载速度

时间:2015-08-13 14:32:58

标签: c# asynchronous

我正在尝试获取当前用户的网络下载速度。在使用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线程)?

2 个答案:

答案 0 :(得分:3)

根据建议您可以制作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()

<强> EDITED 正确指出,WebClient实际上有一个基于任务的异步方法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);
            }
        }
    }

答案 1 :(得分:-1)

尝试`await Task.Run(()=&gt; {//您的代码});

编辑:@JustDevInc我仍然认为你应该使用DownloadAsync。 Task.Run(委托)创建一个新线程,您可能希望避免这种情况。如果您愿意,可以发布一些旧代码,以便我们尝试修复它。

编辑:第一个解决方案原来是两个工作中唯一的一个。 DownloadFileAsync不返回任务,因此无法等待。