使用 Parallel 类进行多线程编码(上)

用 C# 进行多线程编程有很多方式,比如使用 Thread 对象开启一个新线程,但这已经是一种落后的写法了,现在推荐的写法是使用 Parallel 类,它可以让我们像写传统代码一样编写多线程的程序,Parallel 类有三个常用的方法如下:

  • Parallel.For():开启多线程循环执行一段代码
  • Parallel.ForEach():开启多线程遍历处理一个对象集合
  • Parallel.Invoke():开启多线程执行多个方法

下面我们来看看如何使用它们。

1.Parallel.For()的使用

新建一个.net6.0的 控制台应用项目,在项目根目录下新增类 ConcurrencyDemo.cs 用来演示,如下:

在 ConcurrencyDemo.cs 中新增方法 ParallelForPrint(),其作用是调用 Parallel.For() 循环输出1~9,如下:

cs 复制代码
public void ParallelForPrint()
{
   Parallel.For(1, 10, i => {
      Console.WriteLine(string.Format("  i = {0}", i));
   });
}

此方法有3个参数,第1个是循环的起始值,第2个是结束值,第3个是要执行的动作,这里用 Lambda 表达式输出 i.

在 Program.cs 的 Main() 方法中调用,代码如下:

cs 复制代码
static void Main(string[] args)
{
    Console.WriteLine("Hello World!");

    ParallelDemo pdemo = new ParallelDemo();
    pdemo.ParallelForPrint();

    Console.ReadLine();
}

编译后运行程序,得到如下结果:

可以看到,并没有按顺序输出1~9,因为多线程的其中一个特点就是乱序执行,代码的执行顺序是不可控的。

下面我们将方法稍作修改,并与 for 循环做一下对比,看使用 Parallel.For() 做多线程编程比用传统的 for 能快多少。

编译后运行程序,得到如下结果:

和我们期望的不一样,使用 Parallel.For() 花费了更多的时间。如果我们将循环的次数由 20000 改为 20 时候,结果如下:

使用 Parallel.For() 花费的时间依然比 for 多。这说明 Parallel.For() 的使用是有条件的,如果循环内的代码运行的时间很短,它反而更慢,这是因为使用多线程的时候,线程的创建、撤销等是有时间开销的。

下面我们再对方法做一下修改,在循环体内让当前线程休眠 10 毫秒,代码如下,看看会发生什么:

cs 复制代码
public void ParallelForCompareFor()
        {
            //计算 Parallel.For() 的时间
            int total1 = 0;
            Stopwatch watch1 = new Stopwatch();
            watch1.Start(); //开始计时
            Parallel.For(1, 20000, i => {
                total1 += i;
                Thread.Sleep(10);
            });
            watch1.Stop(); //结束计时
            Console.WriteLine(string.Format("  Parallel.For 循环花了 {0} 毫秒。",watch1.ElapsedMilliseconds));

            //计算 for() 的时间
            int total2 = 0;
            Stopwatch watch2 = new Stopwatch();
            watch2.Start(); //开始计时
            for(int j=1;j< 20000; j++)
            {
                total2 += j;
                Thread.Sleep(10);
            }
            watch2.Stop(); //结束计时
            Console.WriteLine(string.Format("  for 循环花了 {0} 毫秒。", watch2.ElapsedMilliseconds));
        }

编译后运行结果如下:

此时 Parallel.For() 的优势便体现出来了。继续将循环次数由 20000 改成 200,结果如下:

使用 Parallel.For() 会快4倍左右。如果再进一步调整休眠时间为 1 毫秒,运行结果如下:

从上面的演示可以看到,Parallel.For() 开启多线程比 for 快的前提是循环体中的代码执行要有一定的时间开销,否则是达不到更快的效果的。

相关推荐
惟恋惜8 小时前
Jetpack Compose 多页面架构实战:从 Splash 到底部导航,每个 Tab 拥有独立 ViewModel
android·ui·架构·android jetpack
沐知全栈开发8 小时前
C 标准库 - <locale.h>
开发语言
湘-枫叶情缘9 小时前
BIZBOK®指南入门教案:框架全景理解与知识地图构建
架构
云舟吖9 小时前
Open-AutoGLM 部署指南:本地大模型控制 Android 手机自动化
架构
老毛肚9 小时前
Java两种代理模式详解
java·开发语言·代理模式
小此方9 小时前
Re:从零开始学C++(二)基础精讲·中篇:引用
开发语言·c++·底层
踏浪无痕9 小时前
自定义 ClassLoader 动态加载:不重启就能加载新代码?
后端·面试·架构
踏浪无痕9 小时前
别重蹈我们的覆辙:脚本引擎选错的两年代价
后端·面试·架构
消失的旧时光-19439 小时前
Java 线程通信:彻底理解 wait / notify(原理 + 图解 + 实战)
java·开发语言
狂胤9 小时前
告别“CV工程师”:手把手教你设计一套 B 端低代码 DSL
架构