为什么异步CTP业绩不佳?不佳、业绩、CTP

2023-09-03 07:08:10 作者:奇迹与不可能实现i

我真的不明白,为什么等待异步没有改善我的$ C $的性能Ç这里像他们应该。

虽然将信将疑,心想,编译器应该重写我的方法,以便下载是并行完成的......但似乎这不是实际发生的事情。 ( 我做意识到等待异步不创建单独的线程;然而,操作系统应该做的parallal的下载,并回叫我code在原来的线程 - ?应该不是的)

现在用我异步等待不当?什么是使用它们的正确方法?

code:

 使用系统;
使用System.Net;
使用的System.Threading;
使用System.Threading.Tasks;

静态类节目
{
    静态INT SumPageSizesSync(字符串[]的URI)
    {
        INT总= 0;
        变种WC =新的Web客户端();
        的foreach(URI中VAR URI)
        {
            共有+ = wc.DownloadData(URI).Length;
            Console.WriteLine(接收同步数据......);
        }
        总回报;
    }

    静态异步任务< INT> SumPageSizesAsync(字符串[]的URI)
    {
        INT总= 0;
        变种WC =新的Web客户端();
        的foreach(URI中VAR URI)
        {
            VAR数据=等待wc.DownloadDataTaskAsync(URI);
            Console.WriteLine(接收async'd CTP数据......);
            共有+ = data.Length;
        }
        总回报;
    }

    静态INT SumPageSizesManual(字符串[]的URI)
    {
        INT总= 0;
        诠释其余= 0;
        的foreach(URI中VAR URI)
        {
            Interlocked.Increment(REF剩下的);
            变种WC =新的Web客户端();
            wc.DownloadDataCompleted + =(S,E)=>
            {
                Console.WriteLine(手动接收异步数据......);
                Interlocked.Add(REF总,e.Result.Length);
                Interlocked.Decrement(REF剩下的);
            };
            wc.DownloadDataAsync(新的URI(URI));
        }
        而(剩余&0){Thread.sleep代码(25); }
        总回报;
    }

    静态无效的主要(字串[] args)
    {
        VAR的URI =新的String []
        {
            //刚刚发现了一个缓慢的网站,向人们展示的问题:)
            http://www.europeanchamber.com.cn/view/home
            http://www.europeanchamber.com.cn/view/home
            http://www.europeanchamber.com.cn/view/home
            http://www.europeanchamber.com.cn/view/home
            http://www.europeanchamber.com.cn/view/home
        };
        {
            VAR开始= Environment.TickCount;
            SumPageSizesSync(URI的);
            Console.WriteLine(同步:{0}毫秒,Environment.TickCount  - 启动);
        }
        {
            VAR开始= Environment.TickCount;
            SumPageSizesManual(URI的);
            Console.WriteLine(手册:{0}毫秒,Environment.TickCount  - 启动);
        }
        {
            VAR开始= Environment.TickCount;
            SumPageSizesAsync(URI)来.Wait();
            Console.WriteLine(异步CTP:{0}毫秒,Environment.TickCount  - 启动);
        }
    }
}
 

输出:

 收到的同步数据...
收到的同步数据...
收到的同步数据...
收到的同步数据...
收到的同步数据...
同步:14336毫秒
手动接收异步数据...
手动接收异步数据...
手动接收异步数据...
手动接收异步数据...
手动接收异步数据...
手册:8627毫秒//几乎快一倍...
接收async'd CTP数据...
接收async'd CTP数据...
接收async'd CTP数据...
接收async'd CTP数据...
接收async'd CTP数据...
异步CTP:13073毫秒//为什么这么慢?
 

解决方案

克里斯的答案几乎是正确的,但引入了竞争条件和各项任务同步块。

一般情况下,最好不要使用任务的延续,如果你有等待 / 异步可用。另外,不要使用了WaitAny / 为WaitAll - 在异步当量是 WhenAny WhenAll

我会写这样的:

 静态异步任务< INT> SumPageSizesAsync(IEnumerable的<字符串>的URI)
{
  //开始一个任务< byte []的>每个下载。
  变种任务= uris.Select(URI =>新Web客户端()DownloadDataTaskAsync(URI));

  //异步等待它们全部完成。
  VAR的结果=等待TaskEx.WhenAll(任务);

  //计算的总和。
  返回results.Sum(结果=> result.Length);
}
 
全球头条丨特朗普喊话伊朗遭回呛 业绩不佳福特忙换帅

I don't really understand why await and async don't improve the performance of my code here like they're supposed to.

Though skeptical, I thought the compiler was supposed to rewrite my method so that the downloads were done in parallel... but it seems like that's not actually happening. (I do realize that await and async do not create separate threads; however, the OS should be doing the downloads in parallal, and calling back my code in the original thread -- shouldn't it?)

Am I using async and await improperly? What is the proper way to use them?

Code:

using System;
using System.Net;
using System.Threading;
using System.Threading.Tasks;

static class Program
{
    static int SumPageSizesSync(string[] uris)
    {
        int total = 0;
        var wc = new WebClient();
        foreach (var uri in uris)
        {
            total += wc.DownloadData(uri).Length;
            Console.WriteLine("Received synchronized data...");
        }
        return total;
    }

    static async Task<int> SumPageSizesAsync(string[] uris)
    {
        int total = 0;
        var wc = new WebClient();
        foreach (var uri in uris)
        {
            var data = await wc.DownloadDataTaskAsync(uri);
            Console.WriteLine("Received async'd CTP data...");
            total += data.Length;
        }
        return total;
    }

    static int SumPageSizesManual(string[] uris)
    {
        int total = 0;
        int remaining = 0;
        foreach (var uri in uris)
        {
            Interlocked.Increment(ref remaining);
            var wc = new WebClient();
            wc.DownloadDataCompleted += (s, e) =>
            {
                Console.WriteLine("Received manually async data...");
                Interlocked.Add(ref total, e.Result.Length);
                Interlocked.Decrement(ref remaining);
            };
            wc.DownloadDataAsync(new Uri(uri));
        }
        while (remaining > 0) { Thread.Sleep(25); }
        return total;
    }

    static void Main(string[] args)
    {
        var uris = new string[]
        {
            // Just found a slow site, to demonstrate the problem :)
            "http://www.europeanchamber.com.cn/view/home",
            "http://www.europeanchamber.com.cn/view/home",
            "http://www.europeanchamber.com.cn/view/home",
            "http://www.europeanchamber.com.cn/view/home",
            "http://www.europeanchamber.com.cn/view/home",
        };
        {
            var start = Environment.TickCount;
            SumPageSizesSync(uris);
            Console.WriteLine("Synchronous: {0} milliseconds", Environment.TickCount - start);
        }
        {
            var start = Environment.TickCount;
            SumPageSizesManual(uris);
            Console.WriteLine("Manual: {0} milliseconds", Environment.TickCount - start);
        }
        {
            var start = Environment.TickCount;
            SumPageSizesAsync(uris).Wait();
            Console.WriteLine("Async CTP: {0} milliseconds", Environment.TickCount - start);
        }
    }
}

Output:

Received synchronized data...
Received synchronized data...
Received synchronized data...
Received synchronized data...
Received synchronized data...
Synchronous: 14336 milliseconds
Received manually async data...
Received manually async data...
Received manually async data...
Received manually async data...
Received manually async data...
Manual: 8627 milliseconds          // Almost twice as fast...
Received async'd CTP data...
Received async'd CTP data...
Received async'd CTP data...
Received async'd CTP data...
Received async'd CTP data...
Async CTP: 13073 milliseconds      // Why so slow??

解决方案

Chris' answer is almost correct, but introduces a race condition and synchronously blocks on all the tasks.

As a general rule, it's best to not use task continuations if you have await/async available. Also, do not use WaitAny / WaitAll - the async equivalents are WhenAny and WhenAll.

I would write it like this:

static async Task<int> SumPageSizesAsync(IEnumerable<string> uris)
{
  // Start one Task<byte[]> for each download.
  var tasks = uris.Select(uri => new WebClient().DownloadDataTaskAsync(uri));

  // Asynchronously wait for them all to complete.
  var results = await TaskEx.WhenAll(tasks);

  // Calculate the sum.
  return results.Sum(result => result.Length);
}