C#并行和多线程1

 Parallel 的使用   parallel.Invoke

var stopWatch = new StopWatch();   //创建一个Stopwatch实例

stopWatch.Start();   //开始计时

stopWatch.Stop();   //停止计时

stopWatch.Reset();  //重置StopWatch

stopWatch.Restart(); //重新启动被停止的StopWatch

stopWatch.ElapsedMilliseconds //获取stopWatch从开始到现在的时间差,单位是毫秒

class Program
    {
        static void Main(string[] args)
        {
            var watch = Stopwatch.StartNew();
            watch.Start();

            Run1();
            Run2();

            Console.WriteLine("我是串行开发,总共耗时:{0}\n", watch.ElapsedMilliseconds);

            watch.Restart();
            Parallel.Invoke(Run1, Run2);
            watch.Stop();
            Console.WriteLine("我是并行开发,总共耗时:{0}", watch.ElapsedMilliseconds);
            Console.Read();
        }
        private static void Run1()
        {
            Console.WriteLine("我是任务一,我跑了1s");
            Thread.Sleep(1000);
        }

        private static void Run2()
        {
            Console.WriteLine("我是任务二,我跑了2s");
            Thread.Sleep(2000);
        }

在这个例子中可以获取二点信息:

第一:一个任务是可以分解成多个任务,采用分而治之的思想。

第二:尽可能的避免子任务之间的依赖性,因为子任务是并行执行,所以就没有谁一定在前,谁一定在后的规定了。

 

Parallel.for

 

 

  class Program
    {
        static void Main(string[] args)
        {
           for(int j=1;j<4;j++)
            {
                Console.WriteLine("\n第{0}次比较", j);
                ConcurrentBag<int> bag = new ConcurrentBag<int>();
                var watch = Stopwatch.StartNew();
                watch.Start();
                for(int i=0;i<20000000;i++)
                {
                    bag.Add(i);
                }
                Console.WriteLine("串行计算:集合有:{0},总共耗时:{1}", bag.Count, watch.ElapsedMilliseconds);
                GC.Collect();

                bag = new ConcurrentBag<int>();
                watch = Stopwatch.StartNew();
                watch.Start();

                //Parallel.for的步行是1
                Parallel.For(0, 20000000, i =>
                {
                    bag.Add(i);
                });
                Console.WriteLine("并行计算:集合有:{0},总共耗时:{1}", bag.Count, watch.ElapsedMilliseconds);
                GC.Collect();
            }
        }
    }

 Parallel.forEach

 static void Main(string[] args)
        {
           for(int j=1;j<4;j++)
            {
                Console.WriteLine("\n第{0}次比较", j);
                ConcurrentBag<int> bag = new ConcurrentBag<int>();
                var watch = Stopwatch.StartNew();
                watch.Start();
                for(int i=0;i<20000000;i++)
                {
                    bag.Add(i);
                }
                Console.WriteLine("串行计算:集合有:{0},总共耗时:{1}", bag.Count, watch.ElapsedMilliseconds);
                GC.Collect();

                bag = new ConcurrentBag<int>();
                watch = Stopwatch.StartNew();
                watch.Start();

                
                Parallel.ForEach(Partitioner.Create(0, 20000000), i =>
                {
                    for (int m = i.Item1; m < i.Item2; m++)
                    {
                        bag.Add(m);
                    }
                });
                Console.WriteLine("并行计算:集合有:{0},总共耗时:{1}", bag.Count, watch.ElapsedMilliseconds);
                GC.Collect();
            }
        }

注意

<1> 如何中途退出并行循环?

      在串行代码中我们break一下就搞定了,但是并行就不是这么简单了,不过没关系,在并行循环的委托参数中提供了一个

ParallelLoopState,该实例提供了Break和Stop方法来帮我们实现。

Break: 当然这个是通知并行计算尽快的退出循环,比如并行计算正在迭代100,那么break后程序还会迭代所有小于100的。

Stop:这个就不一样了,比如正在迭代100突然遇到stop,那它啥也不管了,直接退出。

        static void Main(string[] args)
        {
           for(int j=1;j<4;j++)
            {
                var watch = Stopwatch.StartNew();
                watch.Start();

                ConcurrentBag<int> bag = new ConcurrentBag<int>();
                Parallel.For(0, 20000000, (i, state) =>
                {
                    if(bag.Count==1000)
                    {
                        state.Break();
                        return;
                    }
                    bag.Add(i);
                });
                Console.WriteLine("当前集合有{0}个元素。", bag.Count);
            }
        }

 

<2> 并行计算中抛出异常怎么处理?

 首先任务是并行计算的,处理过程中可能会产生n多的异常,那么如何来获取到这些异常呢?普通的Exception并不能获取到异常,然而为并行诞生的AggregateExcepation就可以获取到一组异常

class Program
{
    static void Main(string[] args)
    {
        try
        {
            Parallel.Invoke(Run1, Run2);
        }
        catch (AggregateException ex)
        {
            foreach (var single in ex.InnerExceptions)
            {
                Console.WriteLine(single.Message);
            }
        }

        Console.Read();
    }

    static void Run1()
    {
        Thread.Sleep(3000);
        throw new Exception("我是任务1抛出的异常");
    }

    static void Run2()
    {
        Thread.Sleep(5000);

        throw new Exception("我是任务2抛出的异常");
    }
}

<3> 并行计算中我可以留一个硬件线程出来吗?

  默认的情况下,底层机制会尽可能多的使用硬件线程,然而我们使用手动指定的好处是我们可以在2,4,8个硬件线程的情况下来进行测量加速比。

class Program
    {
        static void Main(string[] args)
        {
            var bag = new ConcurrentBag<int>();

            ParallelOptions options = new ParallelOptions();

            //指定使用的硬件线程数为1
            options.MaxDegreeOfParallelism = 1;

            Parallel.For(0, 300000, options, i =>
            {
                bag.Add(i);
            });

            Console.WriteLine("并行计算:集合有:{0}", bag.Count);

        }
    }

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值