关于C#中的并行处理

      当我们需要处理大量的数据时,为了能够提高程序的处理速度,我们的做法通常是尽可能的优化算法。然而,当算法不可再优化时,我们就该考虑能否合理的将数据分割成若干个子集,然后去做并行处理。下面是我通过将Excel中的两个Sheet页的数据作比较的例子,目的是得到,A表中有,B表中没有的数据。(两表中各有10000行数据)

       

    class Program
    {
        static void Main(string[] args)
        {
            TableCompare tc = new TableCompare();
            ExcelHelper excelHelper = new         
            ExcelHelper(@"C:\Users\soul\Desktop\test.xlsx");
            DataTable tb1 = excelHelper.ExcelToDataTable("sheet1", true);
            DataTable tb2 = excelHelper.ExcelToDataTable("sheet2", true);
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();

            DataTable retTb = tc.SingleThreadCompare(tb1, tb2);
            //DataTable retTb = tc.MultiThreadCompare(tb1, tb2);
            //DataTable retTb = tc.ParallelCompare(tb1, tb2);

            stopwatch.Stop();
            TimeSpan timeSpan = stopwatch.Elapsed;
            PrintDataTable(retTb);
            Console.WriteLine(timeSpan.TotalSeconds + "秒");
            Console.ReadKey();
        }

        static void PrintDataTable(DataTable table)
        {
            for (int i = 0; i < table.Rows.Count; i++)
            {
                for (int j = 0; j < table.Columns.Count; j++)
                {
                    Console.Write(table.Rows[i][j] + "\t");
                }
                Console.WriteLine();
            }
        }
    }
class TableCompare
    {

        private DataTable retTb;

        public DataTable SingleThreadCompare(DataTable tb1, DataTable tb2)
        {
            retTb = tb1.Clone();

            for (int i = 0; i < tb1.Rows.Count; i++)
            {
                bool isExist = true;
                for (int j = 0; j < tb2.Rows.Count; j++)
                {
                    bool isEquals = true;
                    for (int x = 0; x < tb2.Columns.Count; x++)
                    {
                        if (Convert.ToString(tb1.Rows[i][x]) != Convert.ToString(tb2.Rows[j][x]))
                        {
                            isEquals = false;
                        }
                    }
                    if (isEquals)
                    {
                        isExist = false;
                    }
                }
                if (isExist)
                {
                    retTb.ImportRow(tb1.Rows[i]);
                }
            }
            return retTb;
        }

        public DataTable MultiThreadCompare(DataTable tb1, DataTable tb2)
        {
            retTb = tb1.Clone();
            int workCount = tb1.Rows.Count / 2;
            bool IsComplete1 = false;
            bool IsComplete2 = false;
            Thread t1 = new Thread(() => Run(0, workCount, tb1, tb2, ref IsComplete1));
            Thread t2 = new Thread(() => Run(workCount, tb1.Rows.Count, tb1, tb2, ref IsComplete2));
            t1.Start();
            t2.Start();
            while (!IsComplete1 && !IsComplete2){ }
            return retTb;
        }

        private void Run(int begin, int workCount, DataTable tb1, DataTable tb2, ref bool IsComplete)
        {
            for (int i = begin; i < workCount; i++)
            {
                bool isExist = true;
                for (int j = 0; j < tb2.Rows.Count; j++)
                {
                    bool isEquals = true;
                    for (int x = 0; x < tb2.Columns.Count; x++)
                    {
                        if (Convert.ToString(tb1.Rows[i][x]) != Convert.ToString(tb2.Rows[j][x]))
                        {
                            isEquals = false;
                        }
                    }
                    if (isEquals)
                    {
                        isExist = false;
                    }
                }
                if (isExist)
                {
                    lock (retTb)
                    {
                        retTb.ImportRow(tb1.Rows[i]);
                    }
                }
            }
            IsComplete = true;
        }

        public DataTable ParallelCompare(DataTable tb1, DataTable tb2)
        {
            retTb = tb1.Clone();

            Parallel.For(0, tb1.Rows.Count, i =>
            {
                bool isExist = true;
                for (int j = 0; j < tb2.Rows.Count; j++)
                {
                    bool isEquals = true;
                    for (int x = 0; x < tb2.Columns.Count; x++)
                    {
                        if (Convert.ToString(tb1.Rows[i][x]) != Convert.ToString(tb2.Rows[j][x]))
                        {
                            isEquals = false;
                        }
                    }
                    if (isEquals)
                    {
                        isExist = false;
                    }
                }
                if (isExist)
                {
                    retTb.ImportRow(tb1.Rows[i]);
                }
            });
            return retTb;
        }
    }

SingleThreadCompare只使用一个线程做处理,即在主线程中进行处理。

运行结果如下所示:

       这种处理方式,运行速度较慢,很难让人满意。

       为了提高运行速度,决定采用多线程的方式来处理,即MultiThreadCompare方法,这里我只使用了两个子线程,两个子线程各做一半的数据处理,得到如下的效果:

       速度提升了将近一半,结果是喜人的,不过,在.Net Framework 4.0 以上版本提供了一个并行处理框架Parallel,使用此框架则无需手动创建子线程,即可做并行处理。ParallelCompare方法的处理结果如下:

并行处理后,速度得到了大量的提升。

<think>好的,用户想要了解C#中的并行数据处理,我需要一步步解释清楚。首先,得明确什么是并行处理,以及为什么在C#中使用它。用户可能是开发者,可能已经有一定的C#基础,需要提升数据处理效率。 首先,我应该介绍并行处理的基本概念,说明它如何利用多核处理器提高性能。然后,转到C#的具体实现方式,比如Parallel类、PLINQ、任务并行库等。每个部分需要举例说明,让用户更容易理解。 接下来,需要考虑用户可能关心的线程安全和资源竞争问题。比如,在并行循环中如何避免共享变量的冲突,这时候需要提到锁机制或者使用线程安全的数据结构。同时,性能调优也很重要,比如如何避免过度并行化导致的开销。 用户可能没有提到但需要注意的地方包括异常处理,并行操作中的异常如何捕获和处理,这也是关键点。此外,应用场景的举例能帮助用户判断何时使用并行处理更合适,比如大数据处理或计算密集型任务。 最后,总结一下优缺点,帮助用户权衡是否使用并行处理。可能还需要提醒一些最佳实践,比如测试和性能分析的重要性。确保回答结构清晰,分点说明,同时代码示例用正确的格式,符合用户的要求。</think>在C#中实现并行数据处理主要依赖.NET框架提供的并行编程库,以下是关键技术和实现步骤: 一、核心机制 1. Parallel类(System.Threading.Tasks) - Parallel.For:并行化传统for循环 - Parallel.ForEach:并行遍历集合 - 示例: $$Parallel.For(0, 1000, i => { // 并行处理逻辑 });$$ 2. PLINQ(Parallel LINQ) - 通过.AsParallel()扩展方法启用并行查询 - 示例: $$var results = dataList .AsParallel() .Where(x => x.Value > 100) .Select(x => Process(x));$$ 二、实现要点 1. 线程安全控制 - 使用锁机制(lock) - 线程安全集合(ConcurrentBag<T>, ConcurrentQueue<T>) - 示例: ```csharp object lockObj = new object(); Parallel.ForEach(data, item => { lock(lockObj) { sharedResource.Process(item); } }); ``` 2. 异常处理 - 使用AggregateException捕获并行操作中的异常 - 示例: ```csharp try { Parallel.Invoke(Action1, Action2); } catch (AggregateException ae) { foreach (var ex in ae.InnerExceptions) { // 处理异常 } } ``` 三、性能优化策略 1. 设置并行度 ```csharp ParallelOptions options = new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount / 2 }; ``` 2. 分区策略选择 - 范围分区(数值型数据) - 块分区(非结构化数据) 四、适用场景 1. 计算密集型任务(图像处理/数值计算) 2. IO密集型任务(批量文件处理) 3. 大数据集合处理(超过10万条记录) 五、注意事项 1. 避免过度并行化(根据CPU核心数调整) 2. 注意内存消耗(并行任务内存开销) 3. 使用性能分析工具(Visual Studio诊断工具) 实际案例:并行计算矩阵乘法 ```csharp double[,] ParallelMatrixMultiply(double[,] a, double[,] b) { int size = a.GetLength(0); double[,] result = new double[size, size]; Parallel.For(0, size, i => { for (int j = 0; j < size; j++) { double temp = 0; for (int k = 0; k < size; k++) { temp += a[i,k] * b[k,j]; } result[i,j] = temp; } }); return result; } ``` 建议在实现时: 1. 优先使用高级抽象(PLINQ/Parallel类) 2. 逐步增加并行度测试性能变化 3. 使用Benchmark.NET进行性能测试 4. 注意处理线程亲和性(NUMA架构优化) 并行处理可提升3-8倍性能(取决于任务类型和硬件),但需根据具体场景权衡开发复杂度与性能收益。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值