Hero is coming back

风吹呀吹

风会指引你前进的方向

c# 并行计算

一、并行执行效率对比

数据源

Data = new List<int>() { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
bool ShowProcessExecution = true;

For循环

DateTime dt1 = DateTime.Now;
for(int i=0 ; i<data.Count;i++)
            {
                Thread.Sleep(500);
                if (ShowProcessExecution)
                    Console.WriteLine(data[i]);
            }
            DateTime dt2 = DateTime.Now;
            Console.WriteLine("普通For运行时常:{0}毫秒", (dt2 - dt1).TotalMilliseconds);

Foreach

DateTime dt1 = DateTime.Now;
            foreach(var i in data)
            {
                Thread.Sleep(500);
                if (ShowProcessExecution)
                    Console.WriteLine(data[i]);
            }         
            DateTime dt2 = DateTime.Now;
            Console.WriteLine("普通Foreach运行时常:{0}毫秒", (dt2 - dt1).TotalMilliseconds);

并行For循环

            DateTime dt1 = DateTime.Now;         
            Parallel.For(0, data.Count, (i) =>
                {
                    Thread.Sleep(500);
                    if (ShowProcessExecution)
                        Console.WriteLine(data[i]);
                });
            DateTime dt2 = DateTime.Now;
            Console.WriteLine("并行For运行时常:{0}毫秒", (dt2 - dt1).TotalMilliseconds);

并行Foreach

            DateTime dt1 = DateTime.Now;         
            Parallel.ForEach(data, (i) =>
                {
                    Thread.Sleep(500);
                    if (ShowProcessExecution)
                        Console.WriteLine(data[i]);
                });
            DateTime dt2 = DateTime.Now;
            Console.WriteLine("并行Foreach运行时常:{0}毫秒", (dt2 - dt1).TotalMilliseconds);

效率对比

普通For运行时常:5002毫秒
普通Foreach运行时常:5000毫秒
并行For运行时常:2009毫秒
并行Foreach运行时常:1525毫秒

二、并行中断

Break中断

            Parallel.For(0, data.Count, (i, LoopState) =>
                {
                    if (data[i] > 6)
                    {
                        LoopState.Break();
                    }
                    Thread.Sleep(500);
                    Console.WriteLine(data[i]);
                });
            Console.WriteLine("Stop执行结束。");

Stop中断

            Parallel.For(0, data.Count, (i, LoopState) =>
                {
                    if (data[i] > 6)
                    {
                        LoopState.Stop();
                    }
                    Thread.Sleep(500);
                    Console.WriteLine(data[i]);
                });
            Console.WriteLine("Stop执行结束。");

三、为数组/集合添加项

List是非线程安全的类,多线程操作的时候可能会出现报错

可以使用System.Collections.Concurrent命名空间下

ConcurrentQueue和ConcurrentStack线程安全的类来操作

            List<int> data = new List<int>();
            Parallel.For(0,Program.Data.Count, (i) =>
            {
                if(Program.Data[i]%2==0)
                    data.Add(Program.Data[i]);
            });
            Console.WriteLine("执行完成For.");

ConcurrentQueue

        ConcurrentStack<int> data = new ConcurrentStack<int>();
        Parallel.ForEach(Program.Data, (i) =>
        {
            if (Program.Data[i] % 2 == 0)
                data.Push(Program.Data[i]);//将对象压入栈中
        });
        int R;
        while (data.TryPop(out R))//弹出栈顶对象
        {
            Console.WriteLine(R);
        }
        Console.WriteLine("执行完成ForEach.");

ConcurrentStack

        ConcurrentStack<int> data = new ConcurrentStack<int>();
        Parallel.ForEach(Program.Data, (i) =>
        {
            if (Program.Data[i] % 2 == 0)
                data.Push(Program.Data[i]);//将对象压入栈中
        });
        int R;
        while (data.TryPop(out R))//弹出栈顶对象
        {
            Console.WriteLine(R);
        }
        Console.WriteLine("执行完成ForEach.");

四、并行运算中的局部变量

Foreach局部变量

        long total = 0;
        // data数据源   int为 i 的类型, long 为 局部变量curNumber的类型       
        Parallel.ForEach<int,long>(data,      
            () => 0,                        // curNumber初始化0
            // 为每个迭代调用一次的委托,i是当前索引,LoopState是循环状态,curNumber为局部变量名
            (i, LoopState, curNumber) =>
            {
                curNumber += i;              // 修改局部变量
                return curNumber;            // 传递参数给下一个迭代
            },
            //对每个线程结果执行的最后操作,这里是将所有的结果相加
            (curNumber) => Interlocked.Add(ref total, curNumber)
            );
        Console.WriteLine(total);
    }

For局部变量

        long total = 0;                 
        Parallel.For<long>(0,           // For循环的起点
            data.Count,                 // For循环的终点
            () => 0,                    // 初始化局部变量的方法(long),既为下面的curNumber的初值
            // 为每个迭代调用一次的委托,i是当前索引,LoopState是循环状态,curNumber为局部变量名
            (i, LoopState, curNumber) =>
            {
                curNumber += data[i];    // 修改局部变量
                return curNumber;        // 传递参数给下一个迭代
            },

            //对每个线程结果执行的最后操作,这里是将所有的结果相加
            (curNumber) => Interlocked.Add(ref total, curNumber)
            );
        Console.WriteLine(total);

五、PLinq并行

        var source = Enumerable.Range(1, 10000);
        ConcurrentBag<int> concurrentBag = new ConcurrentBag<int>();
        //查询结果按source中的顺序排序
        var evenNums = from num in source.AsParallel().AsOrdered()
                      // where num % 100 == 0
                      orderby num
                       select num;
        evenNums.ForAll((e) => concurrentBag.Add(e));
        //ForAll的使用
        var query = from num in source.AsParallel()
                    where num % 100 == 0
                    select num;
        query.ForAll((e) => concurrentBag.Add(e));
posted @ 2020-09-21 09:37  风吹呀吹  阅读(486)  评论(0编辑  收藏  举报