如何将AsParallel与async和await关键字一起使用? [英] How do you use AsParallel with the async and await keywords?

查看:223
本文介绍了如何将AsParallel与async和await关键字一起使用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在查看某人的异步示例代码,并注意到其实现方式存在一些问题.在查看代码时,我想知道使用并行方式遍历列表是否比正常地遍历列表更有效.

I was looking at someone sample code for async and noticed a few issues with the way it was implemented. Whilst looking at the code I wondered if it would be more efficient to loop through a list using as parallel, rather than just looping through the list normally.

据我所知,性能几乎没有差别,它们都用尽了每个处理器,并且都花了相同的时间来完成.

As far as I can tell there is very little difference in performance, both use up every processor, and both talk around the same amount of time to completed.

这是第一种方法

var tasks= Client.GetClients().Select(async p => await p.Initialize());

这是第二个

var tasks = Client.GetClients().AsParallel().Select(async p => await p.Initialize());

我能正确假设两者之间没有区别吗?

Am I correct in assuming there is no difference between the two?

完整程序可在下面找到

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            RunCode1();
            Console.WriteLine("Here");
            Console.ReadLine();

            RunCode2();
            Console.WriteLine("Here");

            Console.ReadLine();

        }

        private async static void RunCode1()
        {
            Stopwatch myStopWatch = new Stopwatch();
            myStopWatch.Start();

            var tasks= Client.GetClients().Select(async p => await p.Initialize());

            Task.WaitAll(tasks.ToArray());
            Console.WriteLine("Time ellapsed(ms): " + myStopWatch.ElapsedMilliseconds);
            myStopWatch.Stop();
        }
        private async static void RunCode2()
        {
            Stopwatch myStopWatch = new Stopwatch();
            myStopWatch.Start();
            var tasks = Client.GetClients().AsParallel().Select(async p => await p.Initialize());
            Task.WaitAll(tasks.ToArray());
            Console.WriteLine("Time ellapsed(ms): " + myStopWatch.ElapsedMilliseconds);
            myStopWatch.Stop();
        }
    }
    class Client
    {
        public static IEnumerable<Client> GetClients()
        {
            for (int i = 0; i < 100; i++)
            {
                yield return new Client() { Id = Guid.NewGuid() };
            }
        }

        public Guid Id { get; set; }

        //This method has to be called before you use a client
        //For the sample, I don't put it on the constructor
        public async Task Initialize()
        {
            await Task.Factory.StartNew(() =>
                                      {
                                          Stopwatch timer = new Stopwatch();
                                          timer.Start();
                                          while(timer.ElapsedMilliseconds<1000)
                                          {}
                                          timer.Stop();

                                      });
            Console.WriteLine("Completed: " + Id);
        }
    }
}

推荐答案

区别应该很小.

在您的第一种情况下:

var tasks = Client.GetClients().Select(async p => await p.Initialize());

执行线程将(一次一个)开始为客户端列表中的每个元素执行Initialize. Initialize立即将方法排队到线程池中,并返回未完成的Task.

The executing thread will (one at a time) start executing Initialize for each element in the client list. Initialize immediately queues a method to the thread pool and returns an uncompleted Task.

在第二种情况下:

var tasks = Client.GetClients().AsParallel().Select(async p => await p.Initialize());

执行线程将派生到线程池,并(并行)开始为客户端列表中的每个元素执行Initialize. Initialize具有相同的行为:它立即将方法排队到线程池中并返回.

The executing thread will fork to the thread pool and (in parallel) start executing Initialize for each element in the client list. Initialize has the same behavior: it immediately queues a method to the thread pool and returns.

这两个时间几乎相同,因为您只并行化了少量代码:将方法排队到线程池和返回未完成的Task.

The two timings are nearly identical because you're only parallelizing a small amount of code: the queueing of the method to the thread pool and the return of an uncompleted Task.

如果Initialize在其第一个await之前做了更长的工作(同步),则使用AsParallel可能有意义.

If Initialize did some longer (synchronous) work before its first await, it may make sense to use AsParallel.

请记住,所有async方法(和lambda)都开始被同步执行(请参见我自己的简介).

Remember, all async methods (and lambdas) start out being executed synchronously (see the official FAQ or my own intro post).

这篇关于如何将AsParallel与async和await关键字一起使用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆