第26章 计算限制的异步操作(10)

本文深入探讨了C#中Parallel类的For、ForEach及Invoke方法的使用技巧,并解释了这些方法如何通过线程池线程实现任务的并行处理。此外,还介绍了如何利用委托进行任务的局部初始化、主体操作及局部终结。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

26.6 Parallel的静态For,ForEach和Invoke方法

using System;
using System.Threading;
using System.Threading.Tasks;

namespace ThreadStudy
{
    public class Program
    {
        static void Main(string[] args)
        {
            Parallel.For(98, 101, i => Console.WriteLine("Sum({0})={1};",i,Sum(i)));

            Thread.Sleep(2000);
            Console.WriteLine();

            int[] arr={100,99,98};
            Parallel.ForEach(arr, i => Console.WriteLine("Sum({0})={1};", i, Sum(i)));

            Thread.Sleep(2000);
            Console.WriteLine();

            Parallel.Invoke(() => Console.WriteLine("Sum({0})={1};", 100, Sum(100)),
                () => Console.WriteLine("Sum({0})={1};", 99, Sum(99)),
                () => Console.WriteLine("Sum({0})={1};", 98, Sum(98)));
            Console.ReadKey();
        }

        public static int Sum(int num)
        {
            if (num == 0)
                return 0;
            else
                return num + Sum(num - 1);
        }
    }
}
Parallel的所有方法都让调用线程参与处理。从资源利用的角度说,这是一件好事,因为我们不希望调用线程停下来,等线程池线程做完所有工作才继续。然而,如果调用线程在线程池线程完成自己的那一部分工作之前完成工作,调用线程就会将自己挂起,直到所有工作完成。这也是一件好事,因为这提供了和使用普通for或foreach循环时相同的语义:线程要在所有工作完成后才继续运行。还要注意,如果任何操作抛出一个未处理的异常,你调用的Parallel方法最后会抛出一个AggregateException。

调用Parallel的方法时,有一个前提条件务必牢记:工作项要能并行执行才行。

除此之外,Parallel的方法本身也有开销:委托对象必须分配,而针对每一个工作项,都要调用一次这些委托。

For和ForEach方法有一些重载版本允许传递3个委托:

任务局部初始化委托(localInit),为参与工作的每一个任务都调用一次该委托。这个委托是在任务被要求处理一个工作项之前调用的。

主体委托(body),为参与工作的各个线程所处理的每一项都调用一次该委托。

任务局部终结委托(localFinally),为参与工作的每一个任务都调用一次该委托。这个委托是在任务处理好派遣给它的所有工作之后调用的。即使主体委托代码引发一个未处理的异常,也会调用它。

using System;
using System.Threading;
using System.Threading.Tasks;

namespace ThreadStudy
{
    public class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(Sum());
            Console.ReadKey();
        }

        public static int Sum(int num)
        {
            if (num == 0)
                return 0;
            else
                return num + Sum(num - 1);
        }

        private static Int64 Sum()
        {
            var nums = new int[]{ 1, 2, 3, 4, 5, 6, 7, 8, 9 };
            Int64 masterTotal = 0;
            ParallelLoopResult result = Parallel.ForEach<int, Int64>(nums, 
                () => { return 0; },
                (num, loopstate, index, taskLocalTotal) =>{return taskLocalTotal + num;}, 
                taskLocalTotal => { Interlocked.Add(ref masterTotal, taskLocalTotal); });
            return masterTotal;
        }
    }
}
我们向主体委托传递了一个ParallelLoopState对象。

Parallel的For和ForEach方法都返回一个ParallelLoopResult实例。可通过检查ParrallelLoopResult的属性来了解循环的结果。如果IsCompleted返回true,表明循环运行完成,所有项都得到了处理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值