C#用Parallel.Invoke 方法尽可能并行执行提供的每个线程

本文详细介绍了C#中Parallel.Invoke方法的两种重载,包括无参和带有ParallelOptions参数版本,以及如何与Action[]、Lambda表达式和多线程操作配合使用,提供示例以展示其在并行编程中的应用和注意事项。
摘要由CSDN通过智能技术生成

目录

一、重载

二、Invoke(Action[])

1.定义

2.示例

三、Invoke(ParallelOptions, Action[])

1.定义 

2. 常用的使用方法

(1)示例1

(2)示例2

(3)Stopwatch类


        尽可能并行执行提供的每个操作。使用Parallel.Invoke 方法。

        最简单,最简洁的将串行的代码并行化。 

一、重载

Invoke(Action[])尽可能并行执行提供的每个操作。
Invoke(ParallelOptions, Action[])执行所提供的每个操作,而且尽可能并行运行,除非用户取消了操作。

二、Invoke(Action[])

        尽可能并行执行提供的每个操作。 

1.定义

public static void Invoke (params Action[] actions);

参数
actions    Action[]
要执行的 Action 数组。

例外
ArgumentNullException
actions 参数为 null。

AggregateException
当 actions 数组中的任何操作引发异常时引发的异常。

ArgumentException
actions数组包含 null 个元素。

2.示例

        Invoke方法经常与其他方法、匿名委托和 lambda 表达式配合使用,实现并行方法的线程同步。

// Parallel.Invoke()方法
// 将 Invoke 方法与其他方法、匿名委托和 lambda 表达式结合使用。
namespace ConsoleApp15
{
    class ParallelInvokeDemo
    {
        /// <summary>
        /// 执行每个任务的线程可能不同。
        /// 不同的执行中线程分配可能不同。
        /// 任务可能按任何顺序执行。
        /// </summary>
        static void Main()
        {
            try
            {
                Parallel.Invoke(
                    BasicAction,    // Param #0 - static method
                    () =>           // Param #1 - lambda expression
                    {
                        Console.WriteLine("Method=beta, Thread={0}", Environment.CurrentManagedThreadId);
                    },
                    delegate ()     // Param #2 - in-line delegate
                    {
                        Console.WriteLine("Method=gamma, Thread={0}", Environment.CurrentManagedThreadId);
                    }
                );
            }
            // 一般不会出现异常,但如万一抛出异常, 
            // 它将被包装在 AggregateException 中并传播到主线程。
            catch (AggregateException e)
            {
                Console.WriteLine("An action has thrown an exception. THIS WAS UNEXPECTED.\n{0}", e.InnerException!.ToString());
            }
        }

        static void BasicAction()
        {
            Console.WriteLine("Method=alpha, Thread={0}", Environment.CurrentManagedThreadId);
        }
    }
}
// 运行结果:
/*
Method=beta, Thread=4
Method=alpha, Thread=1
Method=gamma, Thread=10

 */

三、Invoke(ParallelOptions, Action[])

        执行所提供的每个操作,而且尽可能并行运行,除非用户取消了操作。

1.定义 

public static void Invoke (System.Threading.Tasks.ParallelOptions parallelOptions, params Action[] actions);

参数
parallelOptions    ParallelOptions
一个对象,用于配置此操作的行为。

actions    Action[]
要执行的操作数组。

例外
OperationCanceledException
CancellationToken 处于 parallelOptions 设置。

ArgumentNullException
actions 参数为 null。
或 - parallelOptions 参数为 null。
AggregateException
当 actions 数组中的任何操作引发异常时引发的异常。

ArgumentException
actions数组包含 null 个元素。

ObjectDisposedException
在 parallelOptions 中与 CancellationTokenSource 关联的 CancellationToken 已被释放。

注解
此方法可用于执行一组可能并行的操作。 使用结构传入 ParallelOptions 的取消令牌使调用方能够取消整个操作。

2. 常用的使用方法

Parallel.Invoke(
   () => { },
   () => { },
   () => { }
   );

(1)示例1

  • 一个任务是可以分解成多个任务,采用分而治之的思想;
  • 尽可能的避免子任务之间的依赖性,因为子任务是并行执行,所以就没有谁一定在前,谁一定在后的规定了;
  • 主线程必须等Invoke中的所有方法执行完成后返回才继续向下执行。暗示以后设计并行的时候,要考虑每个Task任务尽可能差不多,如果相差很大,比如一个时间非常长,其他都比较短,这样一个线程可能会影响整个任务的性能。这点非常重要;
  • 没有固定的顺序,每个Task可能是不同的线程去执行,也可能是相同的;
namespace ConsoleApp16
{
    internal class Program
    {
       
        private static void Main(string[] args)
        {
            ArgumentNullException.ThrowIfNull(args);
            ParallelMothed();
            static void ParallelMothed()
            {
                Parallel.Invoke(Run1, Run2);  //这里的Run1 Run2 都是方法。
            }
        }
        static void Run1()
        {
            Console.WriteLine("我是任务一,我跑了3s");
            Thread.Sleep(3000);
        }

        static void Run2()
        {
            Console.WriteLine("我是任务二,我跑了5s");
            Thread.Sleep(5000);
        }
    }
}
//运行结果:
/*
我是任务二,我跑了5s
我是任务一,我跑了3s

 */

(2)示例2

        如果调用的方法是有参数的,如何处理?同理,直接带上参数就可以,

Parallel.Invoke(() => Task1("task1"), () => Task2("task2"), () => Task3("task3"));
// Invoke带参数 调用 
using System.Diagnostics;

namespace ConsoleApp17
{
    class ParallelInvoke
    {
        public static void Main(string[] args)
        {
            ArgumentNullException.ThrowIfNull(args);
            Stopwatch stopWatch = new();
            Console.WriteLine("主线程:{0}线程ID : {1};开始", "Main", Environment.CurrentManagedThreadId);
            stopWatch.Start();
            Parallel.Invoke(
                () => Task1("task1"), 
                () => Task2("task2"), 
                () => Task3("task3")
                );
            stopWatch.Stop();
            Console.WriteLine("主线程:{0}线程ID : {1};结束,共用时{2}ms", "Main", Environment.CurrentManagedThreadId, stopWatch.ElapsedMilliseconds);
            Console.ReadKey();
        }

        private static void Task1(string data)
        {
            Thread.Sleep(5000);
            Console.WriteLine("任务名:{0}线程ID : {1}", data, Environment.CurrentManagedThreadId);
        }

        private static void Task2(string data)
        {
            Console.WriteLine("任务名:{0}线程ID : {1}", data, Environment.CurrentManagedThreadId);
        }

        private static void Task3(string data)
        {
            Console.WriteLine("任务名:{0}线程ID : {1}", data, Environment.CurrentManagedThreadId);
        }
    }
}
//运行结果:
/*
主线程:Main线程ID : 1;开始
任务名:task2线程ID : 4
任务名:task3线程ID : 7
任务名:task1线程ID : 1
主线程:Main线程ID : 1;结束,共用时5020ms
 */

(3)Stopwatch类

        提供一组方法和属性,可用于准确地测量运行时间。

        其中,Stopwatch.Start 方法和Stopwatch.Stop 方法详见本文作者写的其他文章,C# 用于准确地测量运行时间的Stopwatch中.Start 方法和Stopwatch.Stop 方法-CSDN博客  https://wenchm.blog.csdn.net/article/details/135735170

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wenchm

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值