C#多线程之Parallel类的用法

 更新时间:2022年04月13日 09:33:09   作者:Ruby_Lu  
这篇文章介绍了C#多线程之Parallel类的用法,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

Parallel类是对线程的一个抽象。该类位于System.Threading.Tasks名称空间中,提供了数据和任务并行性。

Paraller类定义了数据并行地For和ForEach的静态方法,以及任务并行的Invoke的静态方法。Parallel.For()和Parallel.ForEach()方法在每次迭代中调用相同的代码,Paraller.Invoke()允许调用不同的方法。

1.Parallel.For

Parallel.For()方法类似C#语法的for循环语句,多次执行一个任务。但该方法并行运行迭代,迭代的顺序没有定义。

Parallel.For()方法中,前两个参数定义了循环的开头和结束,第三个参数是一个Action委托。Parallel.For方法返回类型是ParallelLoopResult结构,它提供了循环是否结束的信息。

Parallel.For有多个重载版本和多个泛型重载版本。

示例:

static void ForTest()
        {
            ParallelLoopResult plr =
                Parallel.For(0,10,i => {
                    Console.WriteLine("{0},task:{1},thread:{2}",i,Task.CurrentId,Thread.CurrentThread.ManagedThreadId);
                    Thread.Sleep(5000);
                });

            if (plr.IsCompleted)
                Console.WriteLine("completed!");

        }

输出:

任务不一定映射到一个线程上。线程也可以被不同的任务重用。

上面的例子,使用了.NET 4.5中新增的Thread.Sleep方法,而不是Task.Delay方法。Task.Delay是一个异步(http://www.cnblogs.com/afei-24/p/6757361.html)方法,用于释放线程供其它任务使用。

示例:

static void ForTestDelay()
        {
            ParallelLoopResult plr =
                Parallel.For(0, 10,async i => {
                    Console.WriteLine("{0},task:{1},thread:{2}", i, Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
                    await Task.Delay(1000);
                    Console.WriteLine("{0},task:{1},thread:{2}", i, Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
                });

            if (plr.IsCompleted)
                Console.WriteLine("completed!");

            Console.ReadKey();

        }

输出:

上面代码使用了await关键字进行延迟,输出结果显示延迟前后的代码运行在不同的线程中。而且延迟后的任务不再存在,只留下线程,这里还重用了前面的线程。另一个重要的方面是,Parallel类的For方法并没有等待延迟,而是直接完成。parallel类只等待它创建的任务,而不等待其它后台活动。所以上面代码使用了Console.ReadKey();使主线程一直运行,不然很可能看不到后面的输出。

2.提前停止Parallel.For

For()方法的一个重载版本接受第三个Action<int,ParallelLoopState>委托类型的参数。使用这个方法可以调用ParallelLoopState的Break()或Stop()方法,以停止循环。

注意,前面说到,迭代的顺序是没有定义的。

示例:

static void ForStop()
        {
            ParallelLoopResult plr =
                Parallel.For(0,10,(int i,ParallelLoopState pls)=> {
                    Console.WriteLine("{0},task:{1},thread:{2}", i, Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
                    if (i > 5)
                        pls.Break();
                });

            Console.WriteLine("is completed:{0}",plr.IsCompleted);
            Console.WriteLine("最低停止索引:{0}",plr.LowestBreakIteration);
        }

输出:

迭代值在大于5时中断,但其它已开始的任务同时执行。

3.对Parallel.For中的每个线程初始化

Parallel.For方法使用多个线程来执行循环,如果需要对每个线程进行初始化,就可以使用Parallel.For<TLocal>()方法。除了from和to对应的值之外,Parallel.For方法的泛型版本还接受3个委托参数:

第一个委托参数的类型是Func<TLocal>,这个方法仅对用于执行迭代的每个线程调用每一次。

第二个委托参数为循环体定义了委托。该参数类型是Func<int, ParallelLoopState, TLocal, TLocal>。其中第一个参数是循环迭代,第二个参数ParallelLoopState允许停止循环,第三个参数接受从上面参数委托Func<TLocal>返回的值,该委托还需返回一个TLocal类型的值。该方法对每次迭代调用。

第三个委托参数指定一个委托Action<TLocal>,接受第二个委托参数的返回值。这个方法仅对用于执行迭代的每个线程调用每一次。

示例:

static void ForInit()
            {
                ParallelLoopResult plr =
                    Parallel.For(0,10,()=> {
                        Console.WriteLine("init thread:{0},task:{1}",Thread.CurrentThread.ManagedThreadId,Task.CurrentId);
                        return Thread.CurrentThread.ManagedThreadId.ToString();
                    },
                    (i, pls,strInit)=> {
                        Console.WriteLine("body:{0},strInit:{1},thraed:{2},task:{3}",i,strInit,Thread.CurrentThread.ManagedThreadId,Task.CurrentId);
                        return i.ToString();
                    },
                    (strI)=> {
                        Console.WriteLine("finally {0}",strI);
                    });
            }

输出:

4.Parallel.ForEach

Parallel.ForEach方法遍历实现了IEnumerable的集合,类似于foreach,但以异步方式遍历。没有确定遍历顺序。

示例:

static void ForeachTest()
    {
        string[] data = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve" };
        ParallelLoopResult plr =  Parallel.ForEach<string>(data, s =>
        {
            Console.WriteLine(s);
        });
 
        if (plr.IsCompleted)
            Console.WriteLine("completed!");
    }

如果需要中断,可以使用ForEach的重载版本和参数ParallelLoopState。

访问索引器:

ParallelLoopResult plr1 = Parallel.ForEach<string>(data, (s,pls,l) =>
            {
                Console.WriteLine("data:{0},index:{1}",s,l);
            });

5.Parallel.Invoke

如果多个任务并行运行,可以使用Parallel.Invoke方法。该方法允许传递一个Action委托数组。

static void ParallerInvoke()
        {
            Action[] funs = { Fun1,Fun2};

            Parallel.Invoke(funs);
        }

        static void Fun1()
        {
            Console.WriteLine("f1");
            Console.WriteLine("task:{0},thread:{1}", Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
        }
        static void Fun2()
        {
            Console.WriteLine("f2");
            Console.WriteLine("task:{0},thread:{1}", Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
        }

到此这篇关于C#多线程之Parallel类的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • C#多线程系列之原子操作

    C#多线程系列之原子操作

    本文详细讲解了C#多线程的原子操作,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-02-02
  • C#.NET采用HTML模板发送电子邮件完整实例

    C#.NET采用HTML模板发送电子邮件完整实例

    这篇文章主要介绍了C#.NET采用HTML模板发送电子邮件的方法,主要包括了HTML模板、替换函数与邮件函数三部分,是非常实用的功能,需要的朋友可以参考下
    2014-09-09
  • C#线程同步的几种方法总结

    C#线程同步的几种方法总结

    在本篇文章里小编给大家整理的是关于C#线程同步的几种方法总结,需要的朋友们可以学习下。
    2020-02-02
  • C#处理MySql多个返回集的方法

    C#处理MySql多个返回集的方法

    这篇文章主要介绍了C#处理MySql多个返回集的方法,实现了对处理MySql多个返回集进行封装,是非常实用的技巧,需要的朋友可以参考下
    2014-12-12
  • C#求点集的最小包围矩形

    C#求点集的最小包围矩形

    这篇文章主要为大家详细介绍了C#求点集的最小包围矩形,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-09-09
  • C#使用GDI画圆的方法

    C#使用GDI画圆的方法

    这篇文章主要介绍了C#使用GDI画圆的方法,涉及C#使用GDI绘图的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-04-04
  • C#实现客户端弹出消息框封装类实例

    C#实现客户端弹出消息框封装类实例

    这篇文章主要介绍了C#实现客户端弹出消息框封装类,实例分析了C#弹出窗口的实现技巧,非常具有实用价值,需要的朋友可以参考下
    2015-03-03
  • C#中实现线程同步lock关键字的用法详解

    C#中实现线程同步lock关键字的用法详解

    实现线程同步的第一种方式是我们经常使用的lock关键字,它将包围的语句块标记为临界区,这样一次只有一个线程进入临界区并执行代码,接下来通过本文给大家介绍C#中实现线程同步lock关键字的用法详解,一起看看吧
    2016-07-07
  • c# 网络编程之tcp

    c# 网络编程之tcp

    这篇文章主要介绍了c# 网络编程之tcp的的相关资料,帮助大家更好的理解和学习使用c#,感兴趣的朋友可以了解下
    2021-02-02
  • 理解C#中的Lambda表达式

    理解C#中的Lambda表达式

    这篇文章主要介绍了理解C#中的Lambda表达式,本文用实例代码来讲解Lambda表达式,用不同的角度总结对它的认识,需要的朋友可以参考下
    2015-04-04

最新评论