MST
星途 面试题库

面试题:C#中任务并行库TPL基础使用

请简述在C#中如何使用任务并行库TPL创建并启动一个简单的并行任务,比如并行计算一组整数的平方和。同时说明如何处理任务可能抛出的异常。
32.1万 热度难度
编程语言C#

知识考点

AI 面试

面试题答案

一键面试
  1. 使用TPL创建并启动并行任务计算整数平方和
    • 以下是使用Parallel.For方法并行计算一组整数平方和的示例代码:
using System;
using System.Threading.Tasks;

class Program
{
    static void Main()
    {
        int[] numbers = { 1, 2, 3, 4, 5 };
        long sum = 0;

        Parallel.For(0, numbers.Length, i =>
        {
            checked
            {
                long square = (long)numbers[i] * numbers[i];
                lock (typeof(Program))
                {
                    sum += square;
                }
            }
        });

        Console.WriteLine($"平方和为: {sum}");
    }
}
  • 在上述代码中:
    • 定义了一个整数数组numbers
    • 使用Parallel.For方法来并行迭代数组的索引。在Parallel.For的委托中,计算每个数的平方,并将其累加到sum变量中。由于sum是共享变量,为了避免竞态条件,使用lock关键字来确保线程安全的累加操作。checked关键字用于检测可能的算术溢出。
  1. 处理任务可能抛出的异常
    • 使用Parallel.For时,如果在循环体中抛出异常,Parallel.For会捕获这些异常并将它们包装在AggregateException中。可以使用try - catch块来捕获并处理这些异常,如下所示:
using System;
using System.Threading.Tasks;

class Program
{
    static void Main()
    {
        int[] numbers = { 1, 2, 3, 4, 5 };
        long sum = 0;

        try
        {
            Parallel.For(0, numbers.Length, i =>
            {
                checked
                {
                    long square = (long)numbers[i] * numbers[i];
                    lock (typeof(Program))
                    {
                        sum += square;
                    }
                }
            });
        }
        catch (AggregateException ae)
        {
            foreach (var innerException in ae.InnerExceptions)
            {
                if (innerException is OverflowException)
                {
                    Console.WriteLine("发生算术溢出异常: " + innerException.Message);
                }
                else
                {
                    Console.WriteLine("其他异常: " + innerException.Message);
                }
            }
        }

        Console.WriteLine($"平方和为: {sum}");
    }
}
  • 在这个修改后的代码中,try - catch块捕获Parallel.For可能抛出的AggregateException。通过遍历InnerExceptions属性,可以处理每个内部异常。在示例中,针对OverflowException进行了特殊处理,当然也可以根据实际情况处理其他类型的异常。

另外,如果使用Task类创建并行任务,可以如下实现:

  1. 使用Task类创建并启动并行任务计算整数平方和
using System;
using System.Threading.Tasks;

class Program
{
    static void Main()
    {
        int[] numbers = { 1, 2, 3, 4, 5 };
        Task<long>[] tasks = new Task<long>[numbers.Length];

        for (int i = 0; i < numbers.Length; i++)
        {
            int localI = i;
            tasks[i] = Task.Run(() =>
            {
                checked
                {
                    return (long)numbers[localI] * numbers[localI];
                }
            });
        }

        Task.WaitAll(tasks);
        long sum = 0;
        foreach (var task in tasks)
        {
            sum += task.Result;
        }

        Console.WriteLine($"平方和为: {sum}");
    }
}
  • 在上述代码中:
    • 创建了一个Task<long>类型的数组tasks,用于存储每个计算平方的任务。
    • 使用for循环为数组中的每个元素创建一个新的Task,每个任务计算对应数字的平方。注意在Task.Run的委托中,为了避免闭包陷阱,使用了一个局部变量localI
    • 使用Task.WaitAll等待所有任务完成,然后遍历任务数组,累加每个任务的结果得到平方和。
  1. 处理Task可能抛出的异常
    • 同样使用try - catch块来捕获Task可能抛出的异常,如下所示:
using System;
using System.Threading.Tasks;

class Program
{
    static void Main()
    {
        int[] numbers = { 1, 2, 3, 4, 5 };
        Task<long>[] tasks = new Task<long>[numbers.Length];

        try
        {
            for (int i = 0; i < numbers.Length; i++)
            {
                int localI = i;
                tasks[i] = Task.Run(() =>
                {
                    checked
                    {
                        return (long)numbers[localI] * numbers[localI];
                    }
                });
            }

            Task.WaitAll(tasks);
            long sum = 0;
            foreach (var task in tasks)
            {
                sum += task.Result;
            }

            Console.WriteLine($"平方和为: {sum}");
        }
        catch (AggregateException ae)
        {
            foreach (var innerException in ae.InnerExceptions)
            {
                if (innerException is OverflowException)
                {
                    Console.WriteLine("发生算术溢出异常: " + innerException.Message);
                }
                else
                {
                    Console.WriteLine("其他异常: " + innerException.Message);
                }
            }
        }
    }
}
  • 在这个代码中,try - catch块捕获Task.WaitAll可能抛出的AggregateException,同样通过遍历InnerExceptions属性来处理每个内部异常。