• Parallel


    介绍
    C# 4.0 的新特性之并行运算

    • Parallel.For - for 循环的并行运算 
    • Parallel.ForEach - foreach 循环的并行运算 
    • Parallel.Invoke - 并行调用多个任务 
    • Task - 任务,基于线程池。其使我们对并行编程变得更简单,且不用关心底层是怎么实现的
    • PLINQ - 用于对内存中的数据做并行运算,也就是说其只支持 LINQ to Object 的并行运算



    示例
    1、Parallel.For 的 Demo
    Parallel/ParallelFor.aspx.cs

    复制代码
    代码
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;

    namespace CSharp.Parallel
    {
        public partial class ParallelFor : System.Web.UI.Page
        {
            protected void Page_Load(object sender, EventArgs e)
            {
                Normal();
                ParallelForDemo();
            }

            private void Normal()
            {
                DateTime dt = DateTime.Now;

                for (int i = 0; i < 20; i++)
                {
                    GetData(i);
                }

                Response.Write((DateTime.Now - dt).TotalMilliseconds.ToString());
                Response.Write("<br />");
                Response.Write("<br />");
            }

            private void ParallelForDemo()
            {
                DateTime dt = DateTime.Now;

                // System.Threading.Tasks.Parallel.For - for 循环的并行运算
                System.Threading.Tasks.Parallel.For(020, (i) => { GetData(i); });

                Response.Write((DateTime.Now - dt).TotalMilliseconds.ToString());
                Response.Write("<br />");
            }

            private int GetData(int i)
            {
                System.Threading.Thread.Sleep(100);
                Response.Write(i.ToString());
                Response.Write("<br />");
                return i;
            }
        }
    }

    /*
    运行结果:
    0
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    2000.0514

    0
    13
    1
    19
    7
    12
    18
    6
    2
    8
    10
    14
    4
    16
    5
    3
    15
    17
    9
    11
    300.0077
    */
    复制代码



    2、Parallel.ForEach 的 Demo
    Parallel/ParallelForEach.aspx.cs

    复制代码
    代码
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;

    namespace CSharp.Parallel
    {
        public partial class ParallelForEach : System.Web.UI.Page
        {
            private List<int> _data = new List<int>();

            protected void Page_Load(object sender, EventArgs e)
            {
                InitData();

                Normal();
                ParallelForEachDemo();
            }

            private void InitData()
            {
                _data.Clear();
                for (int i = 0; i < 20; i++)
                {
                    _data.Add(i);
                }
            }

            private void Normal()
            {
                DateTime dt = DateTime.Now;

                for (int i = 0; i < 20; i++)
                {
                    GetData(i);
                }

                Response.Write((DateTime.Now - dt).TotalMilliseconds.ToString());
                Response.Write("<br />");
                Response.Write("<br />");
            }

            private void ParallelForEachDemo()
            {
                DateTime dt = DateTime.Now;

                // System.Threading.Tasks.Parallel.ForEach - foreach 循环的并行运算
                System.Threading.Tasks.Parallel.ForEach(_data, (index) => { GetData(index); });

                Response.Write((DateTime.Now - dt).TotalMilliseconds.ToString());
                Response.Write("<br />");
            }

            private int GetData(int i)
            {
                System.Threading.Thread.Sleep(100);
                Response.Write(i.ToString());
                Response.Write("<br />");
                return i;
            }
        }
    }

    /*
    运行结果:
    0
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    2000.0514

    0
    6
    12
    18
    1
    2
    7
    13
    19
    4
    3
    8
    14
    9
    5
    15
    10
    16
    11
    17
    600.0154
    */
    复制代码



    3、Parallel.Invoke 的 Demo
    Parallel/ParallelInvoke.aspx.cs

    复制代码
    代码
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;

    using System.Threading;

    namespace CSharp.Parallel
    {
        public partial class ParallelInvoke : System.Web.UI.Page
        {
            protected void Page_Load(object sender, EventArgs e)
            {
                var tasks = new Action[] { () => Task1(), () => Task2(), () => Task3() };

                // System.Threading.Tasks.Parallel.Invoke - 并行调用多个任务
                System.Threading.Tasks.Parallel.Invoke(tasks);
            }

            private void Task1()
            {
                Thread.Sleep(3000);
                Response.Write("Task1 - " + "ThreadId:" + Thread.CurrentThread.ManagedThreadId.ToString() + " - " + DateTime.Now.ToString("HH:mm:ss"));
                Response.Write("<br />");
            }

            private void Task2()
            {
                System.Threading.Thread.Sleep(3000);
                Response.Write("Task2 - " + "ThreadId:" + Thread.CurrentThread.ManagedThreadId.ToString() + " - " + DateTime.Now.ToString("HH:mm:ss"));
                Response.Write("<br />");
            }

            private void Task3()
            {
                System.Threading.Thread.Sleep(3000);
                Response.Write("Task3 - " + "ThreadId:" + Thread.CurrentThread.ManagedThreadId.ToString() + " - " + DateTime.Now.ToString("HH:mm:ss"));
                Response.Write("<br />");
            }
        }
    }

    /*
    运行结果:
    Task2 - ThreadId:26 - 09:11:58
    Task1 - ThreadId:25 - 09:11:58
    Task3 - ThreadId:24 - 09:11:58
    */
    复制代码



    4、Task 的 Demo
    Parallel/ParallelTask.aspx.cs

    复制代码
    代码
    /*
    Task - 任务,基于线程池。其使我们对并行编程变得更简单,且不用关心底层是怎么实现的
    */

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;

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

    namespace CSharp.Parallel
    {   
        public partial class ParallelTask : System.Web.UI.Page
        {
            protected void Page_Load(object sender, EventArgs e)
            {
                /*
                 * CancellationTokenSource - 取消任务的操作需要用到的一个类
                 *     Token - 一个 CancellationToken 类型的对象,用于通知取消指定的操作
                 *     IsCancellationRequested - 是否收到了取消操作的请求
                 *     Cancel() - 结束任务的执行
                 * ParallelOptions - 并行运算选项
                 *     CancellationToken - 设置一个 Token,用于取消任务时的相关操作
                 *     MaxDegreeOfParallelism - 指定一个并行循环最多可以使用多少个线程
                 */

                CancellationTokenSource cts = new CancellationTokenSource();
                ParallelOptions pOption = new ParallelOptions() { CancellationToken = cts.Token };
                pOption.MaxDegreeOfParallelism = 10;

                Response.Write("开始执行,3.5 秒后结束");
                Response.Write("<br />");

                /*
                 * Task - 任务类
                 *     Factory.StartNew() - 创建并开始一个或一批新任务
                 *     ContinueWith() - 此任务完成后执行指定的另一个任务
                 *     AsyncState - 此任务的上下文对象
                 *     Wait() - 阻塞,直到任务完成
                 */

                Task task0 = Task.Factory.StartNew(() =>
                {
                    Thread.Sleep(3500);
                    cts.Cancel();
                    Response.Write("结束");
                    Response.Write("<br />");

                });

                // 通过 System.Threading.Tasks.Parallel.Invoke 执行任务的时候,可以加入 ParallelOptions 参数,用于对此并行运算做一些配置
                System.Threading.Tasks.Parallel.Invoke(pOption,
                    () => Task1(pOption.CancellationToken),
                    () => Task2(pOption.CancellationToken));


                /*
                 * 一个 Task 内可以包含多个 Task
                Task tasks = new Task(() => 
                {
                    Task.Factory.StartNew(() => Method()); 
                    Task.Factory.StartNew(() => Method2()); 
                    Task.Factory.StartNew(() => Method3()); 
                }); 
                tasks.Start(); 
                // 阻塞,直到整个任务完成
                tasks.Wait(); 
                */


                /*
                 * 带返回值的 Task
                Func<object, long> fun = delegate(object state)
                {
                    return 1.0;
                };
                Task<long> tsk = new Task<long>(fun, "state");
                tsk.Start();
                Response.Write(tsk.Result.ToString()); 
                */
            }
           
            private void Task1(CancellationToken token)
            {
                // 每隔 1 秒执行一次,直到此任务收到了取消的请求
                // 注意:虽然此处是其他线程要向主线程(UI线程)上输出信息,但因为使用了 Task ,所以不用做任何处理
                while (!token.IsCancellationRequested)
                {
                    Response.Write("Task1 - " + "ThreadId: " + Thread.CurrentThread.ManagedThreadId.ToString());
                    Response.Write("<br />");
                    Thread.Sleep(1000);
                }

            }
            private void Task2(CancellationToken token)
            {
                while (!token.IsCancellationRequested)
                {
                    Response.Write("Task2 - " + "ThreadId: " + Thread.CurrentThread.ManagedThreadId.ToString());
                    Response.Write("<br />");
                    Thread.Sleep(1000);
                }
            }
        }
    }

    /*
    运行结果:
    开始执行,3.5 秒后结束
    Task2 - ThreadId: 6
    Task1 - ThreadId: 48
    Task1 - ThreadId: 48
    Task2 - ThreadId: 6
    Task2 - ThreadId: 6
    Task1 - ThreadId: 48
    Task2 - ThreadId: 6
    Task1 - ThreadId: 48
    结束
    */
    复制代码



    5、PLINQ 的 Demo
    Parallel/ParallelPLINQ.aspx.cs

    复制代码
    代码
    /*
    PLINQ - 用于对内存中的数据做并行运算,也就是说其只支持 LINQ to Object 的并行运算
    */

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;

    namespace CSharp.Parallel
    {
        public partial class ParallelPLINQ : System.Web.UI.Page
        {
            protected void Page_Load(object sender, EventArgs e)
            {
                List<int> list = new List<int>();
                for (int i = 0; i < 100; i++)
                {
                    list.Add(i);
                }

                // AsParallel() - 并行运算
                // AsSequential() - 串行运算
                // AsOrdered() - 保持数据的原有顺序(AsSequential()指的是串行运算;AsOrdered()指的是如果在并行运算的前提下,它会把结果先缓存,然后排序,最后再把排序后的数据做输出)
                // AsUnordered() - 可以不必保持数据的原有顺序
                // WithDegreeOfParallelism() - 明确地指出需要使用多少个线程来完成工作
                // WithCancellation(new CancellationTokenSource().Token) - 指定一个 CancellationToken 类型的参数

                ParallelQuery nums = from num in list.AsParallel<int>().AsOrdered<int>()
                                     where num % 10 == 0
                                     select num;

                foreach (var num in nums)
                {
                    Response.Write(num.ToString());
                    Response.Write("<br />");
                }

                // 聚合方法也可以做并行运算
                Response.Write(list.AsParallel().Average().ToString());
                Response.Write("<br />");

                // 自定义聚合方法做并行运算的 Demo(实现一个取集合的平均值的功能)
                double myAggregateResult = list.AsParallel().Aggregate(
                    // 聚合变量的初始值
                    0d,   

                    // 在每个数据分区上,计算此分区上的数据
                    // 第一个参数:对应的数据分区的计算结果;第二个参数:对应的数据分区的每个数据项
                    (value, item) => 
                    {
                        double result = value + item;
                        return result; 
                    },

                    // 根据每个数据分区上的计算结果,再次做计算
                    // 第一个参数:全部数据的计算结果;第二个参数:每个数据分区上的计算结果
                    (value, data) =>
                    {
                        double result = value + data;
                        return result;
                    },

                    // 根据全部数据的计算结果再次计算,得到最终的聚合结果
                    (result) => result / list.Count
                );

                Response.Write(myAggregateResult.ToString());
            } 
        }
    }

    /*
    运行结果:
    0
    10
    20
    30
    40
    50
    60
    70
    80
    90
    49.5
    49.5 
    */
    复制代码



    注:关于并行运算的实例可以参考
    http://code.msdn.microsoft.com/ParExtSamples

  • 相关阅读:
    SQL中的选择判断
    Rsync
    LAMP性能优化的一些建议
    Toad9.7与Oracle11g在X86的Win7下的情况
    IIS中IUSR_和IWAM_:计算机名帐户的用户名和密码的用途
    winform编程中的跨线程访问资源(转)
    MSTDC服务的应用及相关错误的解决方案(转载)
    SQL Server 错误代码详解
    poj 1777梅森素数
    hdu 2815 baby_step c可为非素数
  • 原文地址:https://www.cnblogs.com/zhangyu1024/p/5198795.html
Copyright © 2020-2023  润新知