我如何优化我的ExecuteInParallel函数

时间:2013-01-30 11:17:25

标签: c# multithreading task-parallel-library

我一直在阅读很多关于Parallel .net 4的内容,我不得不说我在使用它时有点困惑。

这是我常见的情况 我被赋予了将大量xml文件迁移到数据库的任务。

我通常必须

  1. 读取Xml文件(100.000)及更多文件并按数字排序(每个文件名为1.xml,2.xml等)。
  2. 保存到数据库。
  3. 我认为以上是并行编程的完美候选。

    从概念上讲,我想一次处理很多文件。

    我目前正在这样做:

    private ResultEventArgs  progressResults=new ResultEventArgs();
    
    public void ExecuteInParallelTest()
    {
        var sw=new Stopwatch();
        sw.Start();
        int index = 0;
        cancelToken = new CancellationTokenSource();
        var parOpts = new ParallelOptions();
        parOpts.CancellationToken = cancelToken.Token;
        parOpts.MaxDegreeOfParallelism = Environment.ProcessorCount;  //It this correct?
    
        FileInfo[] files = myDirectory.EnumerateFiles("*.xml").ToArray();//Is this faster?
        TotalFiles = files.Count();
        try
        {
            Task t1 = Task.Factory.StartNew(() =>
            {
                try
                {
                    Parallel.ForEach(files, parOpts, (file, loopState) =>
                    {
    
                        if (cancelToken.Token.IsCancellationRequested)
                        {
                            cancelToken.Token.ThrowIfCancellationRequested();
                        }
    
                        index = Interlocked.Increment(ref index);
    
                        ProcessFile(file,index);
    
                                    progressResults.Status=InProgress                                   
    
                        OnItemProcessed(TotalFiles,index,etc..);
                    });
                }
                catch (OperationCanceledException ex)
                {
                    OnOperationCancelled(new progressResults
                        {
                            progressResults.Status=InProgress                               
                            progressResults.TotalCount = TotalFiles;
                            progressResults.FileProcessed= index;
                            //etc..                                  
                        });
    
                }
    
                //ContinueWith is used to sync the UI when task completed.
            }, cancelToken.Token).ContinueWith((result) => OnOperationCompleted(new ProcessResultEventArgs
                {
                            progressResults.Status=InProgress
                            progressResults.TotalCount = TotalFiles;
                            progressResults.FileProcessed= index;
                            //etc..
                }), new CancellationTokenSource().Token, TaskContinuationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());
        }
        catch (AggregateException ae)
        {
            //TODO:
        }
       }
    

    我的问题: 我正在使用.net 4.0 使用Parallel是最好/更简单的方法来加速这些文件的处理。 上面的psudo代码是否足够好还是我缺少重要的东西,锁定等等......

    最重要的问题是: 忘记“ProcessFile”,因为我无法控制,因为我无法控制是否有可供选择的空间

    我是否应该以块的形式对文件进行分区,例如1-1000 - 1001-2000-2001-3000可以提高性能(你是如何做到的)

    非常感谢任何回复或链接/代码段,可以帮助我更好地了解如何改进上述代码。

2 个答案:

答案 0 :(得分:0)

您没有收到回复的原因是因为您的代码非常错误。 AsParallel()对GetFiles()没有任何作用,files.Count()实际上迭代了可枚举,因此不仅要读取文件(或只是目录)两次,而是首先执行Count(),然后再遍历它们将读取文件两次,如果目录被修改,可能会产生不一致的计数。 执行Task.Factory.StartNew看起来并不是必需的,因为它是你唯一的任务(它在其中产生并行处理)。 Parallel.ForEach会将所有OperationCancelledException封装到单个AggregateException中,但它只会在所有并行线程完成其工作后执行此操作。

答案 1 :(得分:0)

我保留了代码,因为没人给我提供合适的答案