前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >C#并行与多线程——Parallel并行

C#并行与多线程——Parallel并行

作者头像
李郑
发布于 2019-12-09 03:08:29
发布于 2019-12-09 03:08:29
5.5K00
代码可运行
举报
文章被收录于专栏:漫漫全栈路漫漫全栈路
运行总次数:0
代码可运行

从线程说起

线程分为软件线程和硬件线程。

硬件线程又叫做逻辑内核,我们可以在”任务管理器“中查看”性能“标签页,就能查看电脑的线程数,我们常说的四核八线程,就是指这个,当然这里的四核八线程,其中的八线程是超线程技术,也就是一个核心对应两个线程,从而从硬件层面提升执行性能。

至于软件线程,我们知道一般来说代码都是串行的,就一个主线程,当我们为了实现加速而开了很多工作线程,这些工作线程,也就是软件线程。

线程管理

在.net 4.0之后的版本中,微软给我们提供了一个新的命名空间:System.Threading.Tasks。

这个命名空间提供了一系列的操作类来供我们对线程进行控制。

并行Parallel

在Parallel下面有三个常用的方法invoke,For和ForEach。

先说下StopWatch,这个类主要用于测速,记录时间。

StopWatch 位于 System.Diagnostics命名空间,StopWatch有如下方法:

  • var stopWatch = new StopWatch(); //创建一个Stopwatch实例
  • stopWatch.Start(); //开始计时
  • stopWatch.Stop(); //停止计时
  • stopWatch.Reset(); //重置StopWatch
  • stopWatch.Restart(); //重新启动被停止的StopWatch
  • stopWatch.ElapsedMilliseconds //获取stopWatch从开始到现在的时间差,单位是毫秒

引入System.Threading(MSDN-System.Threading Namespace) 和 System.Threading.Tasks(MSDN-System.Threading.Tasks Namespace) 来使用Parallel。

Parallel.invoke()

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public void Run1()
{
    Thread.Sleep(2000);
    Console.WriteLine("Task 1 is cost 2 sec");
}

public void Run2()
{
    Thread.Sleep(3000);
    Console.WriteLine("Task 1 is cost 3 sec");
}

写两个方法,一个让线程睡眠2s(2000ms),另一个让线程睡眠3s。

通过计时来观察,程序执行的过程,和Parallel的执行。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public void ParallelInvokeMethod()
{
    sp.Start();
    Parallel.Invoke(Run1, Run2);
    sp.Stop();
    Console.WriteLine("Parallel run " + sp.ElapsedMilliseconds + " ms.");

    sp.Restart();
    Run1();
    Run2();
    sp.Stop();
    Console.WriteLine("Normal run " + sp.ElapsedMilliseconds + " ms.");
}

实例化该方法并在mian函数中调用执行,可以从结果中观察到,该方法两段程序的执行结果的差异。

很直观的看出,使用Parallel.Invoke()之后,Run1和Run2是并行执行的,一共用时3s(3000ms左右),而直接运行Run1和Run2则耗时5s。

Parallel.For()

Parallel.For()的用法和 For 类似,直接看代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public void ParallelForMethod()
{
    Stopwatch sp = new Stopwatch();

    sp.Start();

    for (int i = 0; i < 10000; i++)
    {
        for (int j = 0; j < 60000; j++)
        {
            int sum = 0;
            sum+=i;
        }
    }
    sp.Stop();
    Console.WriteLine("NormalFor run " + sp.ElapsedMilliseconds + " ms.");

    sp.Reset();
    sp.Start();
    Parallel.For(0, 10000, item =>
                 {
                     for (int j = 0; j < 60000; j++)
                     {
                         int sum = 0;
                         sum += item;
                     }
                 });
    sp.Stop();
    Console.WriteLine("ParallelFor run " + sp.ElapsedMilliseconds + " ms.");
}

一个使用Parallel.For的双层循环累加,和一个普通的双层循环累加,执行时间的差距却非常大。

Parallel.For实际上是并行执行了循环,因为内部只是一个单纯的累加,因此效率差异明显,但是并非所有的场景都适合使用并行循环

修改一下上面的方法。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制

public void ParallelForMethodFromGV()
{
    var obj = new Object();
    long num = 0;

    sp.Start();
    for (int i = 0; i < 10000; i++)
    {
        for (int j = 0; j < 60000; j++)
        {
            num++;
        }
    }
    sp.Stop();
    Console.WriteLine("NormalFor run " + sp.ElapsedMilliseconds + " ms.");

    sp.Reset();
    sp.Start();
    Parallel.For(0, 10000, item =>
    {
        for (int j = 0; j < 60000; j++)
        {
            lock (obj)
            {
                num++;
            }
        }
    });
    sp.Stop();
    Console.WriteLine("ParallelFor run " + sp.ElapsedMilliseconds + " ms.");

}

改为操作一个全局变量的累加,这个时候由于并行请求,需要等待调用内存中的全局变量num,效率反而降低。

同样的,由于并行处理的原因,For的结果并不是按照原有顺序进行的:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public void ParallelForCW()
{
    Parallel.For(0, 100, i => { Console.Write(i + "\t"); });
}

Parallel.For虽然在执行效率上高于For,但是必须要在符合条件的场景下使用!

Parallel.ForEach()

ForEach是For的拓展,用于遍历数组或则list对象,实际上的意义和用法与For相同,因此Parallel中的 ForEach也是这般,这里不过多赘述。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Stopwatch sp = new Stopwatch();
public void ParallelForEachMethod()
{
    int[] arr = { 0,1,2,2,3,3,123,123,12,31,231,23,1,231,3,13,1,231,23,123,1,23,123,12,31,23,123,12,312,3,123,1,23};
    List<int> list = new List<int>(arr);
    List<int> list2 = new List<int>(arr);

    sp.Start();
    Parallel.ForEach(arr, item =>
    {
        list.Add(item);
    });
    sp.Stop();
    Console.WriteLine("ParallelForEach run " + sp.ElapsedMilliseconds + " ms.");

    sp.Restart();
    foreach (var item in arr)
    {
        list2.Add(item);
    }
    sp.Stop();
    Console.WriteLine("NormalForEach run " + sp.ElapsedMilliseconds + " ms.");
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019-04-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
C# 多线程 Parallel.ForEach 和 ForEach 效率问题研究及理解
最近要做一个大数据dataTable循环操作,开始发现 运用foreach,进行大数据循环,并做了一些逻辑处理。在循环中耗费的时间过长。后来换成使用Parallel.ForEach来进行循环。 一开始认为, 数据比较大时,Parallel.ForEach肯定比 ForEach效率高,后来发现,其实并不是这样。
全栈程序员站长
2022/09/09
1.2K0
C# 多线程 Parallel.ForEach 和 ForEach 效率问题研究及理解
并行编程和任务(一)
  并发、并行。同步、异步、互斥、多线程。我太难了。被这些词搞懵了。前面我们在写.Net基础系列的时候写过了关于.Net的异步编程。那么其他的都是些什么东西呀。今天我们首先就来解决这个问题。把这些词搞懂搞透。理清逻辑。然后最后我们进入并行编程的介绍。
小世界的野孩子
2019/11/07
9240
并行编程和任务(一)
.NET Thread、Task或Parallel实现多线程的使用总结
多线程是指程序中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的任务,也就是说允许单个程序创建多个并行执行的线程来完成各自的任务。
郑子铭
2023/08/30
3340
.NET Thread、Task或Parallel实现多线程的使用总结
使用C#封装一个多线程测试工具
这个工具可以帮助开发者测试多线程程序的性能、线程安全性和并发问题。我们将实现以下功能:
软件架构师Michael
2025/01/24
1080
C#如何:编写简单的 Parallel.ForEach 循环
本文档使用 lambda 表达式在 PLINQ 中定义委托。 如果不熟悉 C# 或 Visual Basic 中的 lambda 表达式,请参阅 PLINQ 和 TPL 中的 Lambda 表达式。
全栈程序员站长
2022/09/09
1.6K0
C# Parallel 类指南
Parallel是.NET中的一个类,用于简化并行编程。它提供了一组方便的方法,帮助开发人员在多核处理器和多线程环境下执行任务,从而加速应用程序的执行。Parallel类可以自动将任务分成更小的子任务,并在多个线程上并行执行这些子任务,从而使利用多核处理器的能力变得更加容易和有效。Parallel还提供了一套机制来处理任务的取消和异常,减少了线程管理的复杂性,让开发人员更专注于任务本身。
Power
2025/04/02
460
C# Parallel
Parallel 具有多种静态方法,用于并行执行一组操作。这些方法可以显著提高处理大量数据时的性能,因为它们可以将工作负载分配到多个处理器核心或线程上。
JusterZhu
2023/09/18
3150
C# Parallel
使用.NET并行任务库(TPL)与并行Linq(PLINQ)充分利用多核性能
记录一下前段时间用到的.NET框架下采用并行策略充分利用多核CPU进行优化的一个方法
GuZhenYin
2024/09/26
2350
使用.NET并行任务库(TPL)与并行Linq(PLINQ)充分利用多核性能
C#数据并行和任务并行
      Paraller.For()方法类似于C#的for循环语句,也是多次执行一个任务。使用Paraller.For()方法,可以并行运行迭代,迭代的顺序没有定义。
yaphetsfang
2020/07/30
1.6K0
C#数据并行和任务并行
.NET并行编程实践(一:.NET并行计算基本介绍、并行循环使用模式)
本文介绍了.NET并行编程的基本知识,包括.NET中的并行编程模式、并行循环、并行LINQ等。通过这些知识,读者可以更好地理解.NET并行编程的基础,并更有效地使用.NET进行并行编程。
王清培
2018/01/05
1.9K0
.NET并行编程实践(一:.NET并行计算基本介绍、并行循环使用模式)
.Net多线程编程—System.Threading.Tasks.Parallel
System.Threading.Tasks.Parallel类提供了Parallel.Invoke,Parallel.For,Parallel.ForEach这三个静态方法。 1 Parallel.Invoke 尽可能并行执行所提供的每个操作,除非用户取消了操作。 方法: 1)public static void Invoke(params Action[] actions); 2)public static void Invoke(ParallelOptions parallelOptions, par
甜橙很酸
2018/03/08
1.3K0
4.0中的并行计算和多线程详解(一)
转自:https://www.cnblogs.com/sorex/archive/2010/09/16/1828214.html
vv彭
2021/01/27
1.7K0
4.0中的并行计算和多线程详解(一)
【愚公系列】2023年01月 .NET CORE工具案例-RedLock.net实现分布式锁
在分布式系统中,常常需要协调他们的动作。如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要互斥来防止彼此干扰来保证一致性,这个时候,便需要使用到分布式锁。
愚公搬代码
2023/01/03
6220
【愚公系列】2023年01月 .NET CORE工具案例-RedLock.net实现分布式锁
C#并发编程之初识并行编程
之前微信公众号里有一位叫sara的朋友建议我写一下Parallel的相关内容,因为手中商城的重构工作量较大,一时之间无法抽出时间。近日,这套系统已有阶段性成果,所以准备写一下Parallel的相关内容,正好也延续之前的C#并发编程系列。
AI.NET 极客圈
2020/05/18
1.3K0
C#多线程学习一
一、概述:C#支持多线程并行执行程序,一个线程有他单独的执行路径,能够与其他线程同时执行,一个程序是由一个单线程开始,该单线程由CLR(公共语言运行时)和操作系统创建而成,并具有多线程创建额外线程的功能。 1、创建线程的方法 <1>、通过Thread类来创建线程,ThreadStart委托创建线程从哪里开始运行的方法 using System; using System.Threading; namespace Mulithreading{ class CreateThreadMethods{
郑小超.
2018/01/24
1.1K0
C#多线程学习一
Thread、ThreadPool、Task、Parallel、Async和Await基本用法、区别以及弊端
ThreadPool是Thread的一个升级版,ThreadPool是从线程池中获取线程,如果线程池中又空闲的元素,则直接调用,如果没有才会创建,而Thread则是会一直创建新的线程,要知道开启一个线程就算什么事都不做也会消耗大约1m的内存,是非常浪费性能的,接下来我们写一个例子来看一下二者的区别:
AI.NET 极客圈
2019/08/14
1.8K0
C#:数据并行
在 Action<int, ParallelLoopState>等这样的action中,使用如下的代码可以实现stop和break:
sherlock99
2018/07/24
7410
C# 多线程七之Parallel
关于Parallel不想说太多,因为它是Task的语法糖,至少我是这么理解的,官方文档也是这么说的,它本身就是基本Task的.假设我们有一个集合,不管是什么集合,我们要遍历它,首先想到的是For(如何涉及到修改或者读可以用for)或者Foreach(如果单纯的读),但是它两是同步的去操作集合,但是使用Parallel的静态For或者Foreach那就可以让多个线程参与这个工作,这样就能充分的利用CPU,但是你需要考虑CPU上下文产生的性能消耗,以及Parallel本身的性能消耗,所以,这也能解释为什么,你的循环里面执行的是不耗时的操作,使用for或者foreach的速度比使用Parallel的要快,所以使用Parallel还是要慎重.而且使用Parallel还需要注意的一点就是,不能有多线程争用问题,就是你的循环体里面不能有操作静态资源的操作.如果真的需要,那你可以加锁,但是那就失去它的优势了.
郑小超.
2018/12/24
1.4K0
C# 多线程编程
1.如果只是启动一个新线程,不需要传入参数,不需要线程返回结果,可以直接使用ThreadStart(),
全栈程序员站长
2022/09/07
6380
多线程系列(一)多线程基础
进程:进程是计算机的概念,程序在服务器运行时占据全部计算资源的总和,一个应用程序运行起来就是一个进程,打开windows的任务管理器,如下图
指尖改变世界
2020/08/22
1K0
相关推荐
C# 多线程 Parallel.ForEach 和 ForEach 效率问题研究及理解
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验