并行开发-paraller(代码片段)

gnailgnepgnaw gnailgnepgnaw     2023-03-12     760

关键词:

并行开发的概念

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

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性能比较

 

parallel类

...Threading.Tasks名称空间中,提供了数据和任务并行性。  Paraller类定义了数据并行地For和ForEach的静态方法,以及任务并行的Invoke的静态方法。Parallel.For()和Parallel.ForEach()方法在每次迭代中调用相同的代码,Paraller.Invoke()允许调用... 查看详情

.net中并行开发优化(代码片段)

...程挑战:对大数组中的所有元素求和。现在可以通过使用并行性来轻松优化这一点,特别是对于具有数千或数百万个元素的巨大阵列,还有理由认为,并行处理时间应该与常规时间除以CPU核心数一样多。事实证明,这一壮举并不... 查看详情

初识mapreduce(代码片段)

...的计算。对于大数据量的计算,通常采用的处理手法就是并行计算。但对许多开发者来说,自己完完全全实现一个并行计算程序难度太大,而MapReduce就是一种简化并行计算的编程模型,它使得那些没有多有多少并行计算经验的开... 查看详情

8天玩转并行开发——第四天同步机制(上)(代码片段)

  在并行计算中,不可避免的会碰到多个任务共享变量,实例,集合。虽然task自带了两个方法:task.ContinueWith()和Task.Factory.ContinueWhenAll()来实现任务串行化,但是这些简单的方法远远不能满足我们实际的开发需要,从.net4.0... 查看详情

搭建并行开发环境mpich2(代码片段)

平台信息Description:CentOSLinuxrelease7.6.1810(Core)注意事项安装BLAS之前需要:安装GCC/GFortran环境安装步骤下载mpich-3.2.1.tar.gz:wgethttp://www.mpich.org/static/downloads/3.2.1/mpich-3.2.1.tar.gz解压安装包:tarxzfmpich-3.2.1.tar.gz 查看详情

8天玩转并行开发——第五天同步机制(下)(代码片段)

...篇,我们继续说下.net4.0中的同步机制,是的,当出现了并行计算的时候,轻量级别的同步机制应运而生,在信号量这一块出现了一系列的轻量级,今天继续介绍下面的3个信号量 CountdownEvent,SemaphoreSlim,ManualResetEventSlim。 ... 查看详情

指令级并行(代码片段)

基于《计算机体系结构:量化研究方法》第3章指令级并行及其开发本章内容主要面向计算机设计人员和编译器开发者,因此只记录一些感兴趣的点。介绍指令级并行(ILP)就是多条指令同时执行,达到提升性能的目的。因为执... 查看详情

cuda并行程序设计开发环境搭建与远程调试(代码片段)

课题需要用到GPU加速。目前使用的台式电脑只有核心显卡,而实验室有一台服务器装有NVIDIAGTX980独显。因此,想搭建一个CUDA的开发环境,来实现在台式机上面开发cuda程序,程序在服务器而不必每次都跑去服务器上面。目前找到... 查看详情

微软c++并行库pplx的基本用法(代码片段)

前言并行计算库充分利用多核的优势,通过并行运算提高程序效率,业界有两个知名的c++并行库,一个是intel开发的TBB,一个是微软开发的PPL。TBB(Intel®ThreadingBuildingBlocks)TBB是intel用标准c++写... 查看详情

微软c++并行库pplx的基本用法(代码片段)

前言并行计算库充分利用多核的优势,通过并行运算提高程序效率,业界有两个知名的c++并行库,一个是intel开发的TBB,一个是微软开发的PPL。TBB(Intel®ThreadingBuildingBlocks)TBB是intel用标准c++写... 查看详情

8天玩转并行开发——第六天异步编程模型(代码片段)

 在.net里面异步编程模型由来已久,相信大家也知道Begin/End异步模式和事件异步模式,在task出现以后,这些东西都可以被task包装起来,可能有人会问,这样做有什么好处,下面一一道来。 一:Begin/End模式1:委托  ... 查看详情

8天玩转并行开发——第二天task的使用(代码片段)

   在我们了解Task之前,如果我们要使用多核的功能可能就会自己来开线程,然而这种线程模型在.net4.0之后被一种称为基于“任务的编程模型”所冲击,因为task会比thread具有更小的性能开销,不过大家肯定会有... 查看详情

8天玩转并行开发——第八天用vs性能向导解剖你的程序(代码片段)

  最后一篇,我们来说说vs的“性能向导",通常我们调试程序的性能一般会使用Stopwatch,如果希望更加系统的了解程序,我们就需要用到”性能向导“,通过性能报告便于我们快速的发现并找到潜在的性能问题。&n... 查看详情

8天玩转并行开发——第七天简要分析任务与线程池(代码片段)

    其实说到上一篇,我们要说的task的知识也说的差不多了,这一篇我们开始站在理论上了解下“线程池”和“任务”之间的关系,不管是说线程还是任务,我们都不可避免的要讨论下线程池,然而在.... 查看详情

git并行开发「分支」(代码片段)

文章目录Git并行开发「分支」一、分支的概念二、分支的创建与切换三、分支的合并区别四、合并的冲突及解决1、制造冲突2、解决冲突五、利用分支debug1、现场保护2、创建分支并在分支进行debug3、恢复现场六、惯用分支名Git并... 查看详情

git并行开发「分支」(代码片段)

文章目录Git并行开发「分支」一、分支的概念二、分支的创建与切换三、分支的合并区别四、合并的冲突及解决1、制造冲突2、解决冲突五、利用分支debug1、现场保护2、创建分支并在分支进行debug3、恢复现场六、惯用分支名Git并... 查看详情

git并行开发「分支」(代码片段)

文章目录Git并行开发「分支」一、分支的概念二、分支的创建与切换三、分支的合并区别四、合并的冲突及解决1、制造冲突2、解决冲突五、利用分支debug1、现场保护2、创建分支并在分支进行debug3、恢复现场六、惯用分支名Git并... 查看详情

java开发两年:dockercommit命令(代码片段)

...事务、分布式定时任务等多个模块,支持多业务系统并行开发,支持多服务并行开发,可以作为后端服务的开发脚手架 查看详情