码迷,mamicode.com
首页 > 其他好文 > 详细

并行开发-Paraller

时间:2019-04-06 09:14:24      阅读:147      评论:0      收藏:0      [点我收藏+]

标签:重载方法   结果   run   9.png   常用   stat   需要   简单   code   

并行开发的概念

并行开发要做的事情就是将任务分摊给硬件线程去并行执行来达到负载和加速,传统的代码都是串行的,就一个主线程,当我们为了实现加速而开了很多工作线程,这些工作线程就是软件线程

Parallel的使用

Parallel类是对线程的抽象,位于System.Threading.Tasks名称空间下,提供了任务和数据并行性.在Parallel下有三个常用的方法Invoke,For和ForEach,其中Parallel.Invoke用于任务并行性,Parallel.ForEach用于数据并行性

Parallel.Invoke

如果多个任务应并行运行,就可以使用Parallel.Invoke()方法,可以最简单,最简洁的将串行的代码并行化

简单应用

class ThreadTest
{
    static void Main(string[] args)
    {
        var watch = Stopwatch.StartNew();
        watch.Start();
        Run1();
        Run2();
        Run3();
        watch.Stop();
        Console.WriteLine("串行开发,总耗时{0}", watch.ElapsedMilliseconds);

        watch.Restart();

        Parallel.Invoke(Run1, Run2, Run3);
        watch.Stop();
        Console.WriteLine("并行开发,总耗时{0}", watch.ElapsedMilliseconds);
        Console.ReadKey();
    }
    static void Run1()
    {
        Console.WriteLine("Run1,我需要1s");
        Thread.Sleep(1000);
    }
    static void Run2()
    {
        Console.WriteLine("Run2,我需要3s");
        Thread.Sleep(3000);
    }
    static void Run3()
    {
        Console.WriteLine("Run3,我需要4s");
        Thread.Sleep(4000);
    }
}

 技术图片

主程序启动时,先顺序调用Run1(),Run()2,Run3()方法,这是串行的,而后使用Parallel.Invoke()将三个方法并行调用,可见耗时是有明显下降的

执行顺序

static void Main(string[] args)
{
    Console.WriteLine("主线程启动,线程ID:{0}", Thread.CurrentThread.ManagedThreadId);
    Parallel.Invoke(() => Run1("task1"), () => Run2("task2"), () => Run3("task3"));
    Console.WriteLine("主线程结束,线程ID:{0}", Thread.CurrentThread.ManagedThreadId);
    Console.ReadKey();
}
static void Run1(string taskName)
{
    Console.WriteLine("任务名:{0}线程ID:{1}", taskName, Thread.CurrentThread.ManagedThreadId);
    for (int i = 0; i < 5; i++)
    {
        Console.WriteLine("a");
    }
}
static void Run2(string taskName)
{
    Console.WriteLine("任务名:{0}线程ID:{1}", taskName, Thread.CurrentThread.ManagedThreadId);
    for (int i = 0; i < 5; i++)
    {
        Console.WriteLine("b");
    }
}
static void Run3(string taskName)
{
    Console.WriteLine("任务名:{0}线程ID:{1}", taskName, Thread.CurrentThread.ManagedThreadId);
    for (int i = 0; i < 5; i++)
    {
        Console.WriteLine("c");
    }
}

技术图片

结果可知:

      1、没有固定顺序,每个Task可能是不同的线程去执行,也可能是相同的

      2、主线程必须等Invoke中的所有方法执行完成后返回才继续向下执行,以后设计并行的时候,要考虑每个Task任务尽可能差不多,如果相差很大,比如一个时间非常长,其他都比较短,这样一个线程可能会影响整个任务的性能。这点非常重要(就是说Invoke会阻塞主线程)

异常产生

static void Main(string[] args)
{
    Console.WriteLine("主线程启动,线程ID:{0}", Thread.CurrentThread.ManagedThreadId);
    try
    {
        Parallel.Invoke(() => Run1("task1"), () =>
        {
            throw new Exception("出现异常");
        }, () => Run2("task2"), () => Run3("task3"));
    }
    catch (AggregateException ex)
    {
        foreach (var item in ex.InnerExceptions)
        {
            Console.WriteLine(item);
        }
    }
    Console.WriteLine("主线程结束,线程ID:{0}", Thread.CurrentThread.ManagedThreadId);
    Console.ReadKey();
}

技术图片

Invoke方法中调用了一个产生异常的方法,但是结果发现异常并不会影响其它方法及主线程的执行

重载方法ParallelOptions 的使用

主要理解两个参数:

     CancellationToken:控制线程的取消
     MaxDegreeOfParallelism :设置最大的线程数,有时候可能会跑遍所有的内核,为了提高其他应用程序的稳定性,就要限制参与的内核

Parallel.For

串行代码中也有一个for,但是那个for并没有用到多核,而Paraller.For它会在底层根据硬件线程的运行状况来充分的使用所有的可利用的硬件线程

static void Main(string[] args)
{
    for (int i = 0; i < 3; i++)
    {
        ConcurrentBag<int> bag = new ConcurrentBag<int>();
        var watch = Stopwatch.StartNew();
        watch.Start();

        for (int j = 0; j < 20000000; j++)
        {
            bag.Add(i);
        }
        watch.Stop();
        Console.WriteLine("串行添加,总数20000000,耗时{0}", watch.ElapsedMilliseconds);
        GC.Collect();
        watch.Restart();
        Parallel.For(0, 20000000, j =>
        {
            bag.Add(j);
        });
        watch.Stop();
        Console.WriteLine("并行添加,总数20000000,耗时{0}", watch.ElapsedMilliseconds);
        Console.WriteLine("***********************************");
        GC.Collect();
    }
    Console.ReadKey();
}

向一个线程安全的集合插入数据,使用串行的for耗时与使用并行的Parallel.For差异

技术图片

Parallel.For提前中断

 

Parallel.ForEach

ForEach的特点在于可以将数据进行分区,每一个小区内实现串行计算,分区采用Partitioner.Create实现

Parallel.For/for   Parallel.ForEach/foreach性能比较

 

并行开发-Paraller

标签:重载方法   结果   run   9.png   常用   stat   需要   简单   code   

原文地址:https://www.cnblogs.com/GnailGnepGnaw/p/10660547.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!