TPL DataFlow - 仅在首次运行时调用完成

时间:2015-02-22 16:32:41

标签: c# winforms concurrency task-parallel-library tpl-dataflow

我正在尝试使用.Net 4.5在Windows窗体应用程序中创建我的第一个TPL DataFlow服务。

概述,应用程序从.csv文本文件加载和解析一些数据,并在一些处理/询问后生成SQL数据库记录(使用实体框架数据访问层)。一旦加载了所有记录,应用程序就会通过迭代生成的数据库记录来生成结果文本文件。这是工作流程......

loadListFile: iterates through text file and posts to...
   + createStateRecord: generates the database records
      + setStateRecordStatus: updates the UI for each record

WhenAll records have been created...

generateReport: iterates through the database and posts to
    + writeReport: writes a summary record to a text file
       + setReportStatus: updates the UI to show report progress

我很欣赏我可以将这两个任务之间的关系构建为工作流程的一部分,但是现在我想将它们分开

我遇到的问题是应用程序/ TPL工作流似乎在第一次传递时正常工作,但如果重置UI并且第二次运行该进程,则永远不会调用writeReport.Completion方法 - 即使调用writeReport.Complete()方法。

这是完整的方法(从表单上的“click”偶数处理程序中调用)。

private async void ProcessData()
{
    /********************************************************************/
    /** Create State records                                            */
    /********************************************************************/
    var createStateRecord = new TransformBlock
        <CheckData, CheckResult>(checkData =>
        {
            return DalServices.CreateStateRecord(checkData);
        }, new ExecutionDataflowBlockOptions
        {
            CancellationToken = _cancellationToken.Token,
            MaxDegreeOfParallelism = 10
        });

    var setStateRecordStatus = new ActionBlock <CheckResult>(
        result =>
        {
            Interlocked.Increment(ref _noRecordsProcessed);
            if (!result.Success)
                Interlocked.Increment(ref _noRecordsFailed);

            pbarLoad.Minimum = 0;
            pbarLoad.Maximum = _noRecordsInFile;
            pbarLoad.Value = _noRecordsProcessed;
        }, new ExecutionDataflowBlockOptions
        {
            CancellationToken = _cancellationToken.Token,
            TaskScheduler = TaskScheduler
                .FromCurrentSynchronizationContext()
        });

     var loadListFile = new ActionBlock<string>(
        listFilePath =>
        {
            using (var reader =
                new DataProviderService(_listFileInfo.FullName))
            {
                _noRecordsProcessed = 0;
                _noRecordsInFile = reader.NoRows;

                foreach (var item in reader)
                {
                    createStateRecord.Post(new CheckData(item));
                }
                createStateRecord.Complete();
            }
        },
        new ExecutionDataflowBlockOptions
        {
            CancellationToken = _cancellationToken.Token
        });

    /*
     * Link StateRecord tasks
     */
    createStateRecord.LinkTo(setStateRecordStatus);
    createStateRecord.Completion.ContinueWith(t =>
        {
            if (t.IsFaulted)
            {
                ((IDataflowBlock) setStateRecordStatus)
                    .Fault(t.Exception);
                return;
            }
            setStateRecordStatus.Complete();
        }, _cancellationToken.Token);

    /********************************************************************/
    /** Reporting tasks                                                 */
    /********************************************************************/
    var writeReport = new TransformBlock<ReportData, State>(
        reportData =>
        {
            using (
                var writer = new StreamWriter(
                reportData.ResultsFilePath, true))
            {
                writer.WriteLine(reportData.State.ToString());
            }
            return reportData.State;
        },
            new ExecutionDataflowBlockOptions
            {
                CancellationToken = _cancellationToken.Token,
                MaxDegreeOfParallelism = 1
            });

        var setReportStatus = new ActionBlock<State>(
            result =>
            {
                Interlocked.Increment(ref _noRecordsReported);
                pbarReport.Minimum = 0;
                pbarReport.Maximum = _noRecordsInFile;
                pbarReport.Value = _noRecordsReported;
            },
            new ExecutionDataflowBlockOptions
            {
                CancellationToken = _cancellationToken.Token,
                TaskScheduler = TaskScheduler
                    .FromCurrentSynchronizationContext()
            });

        var generateReport = new ActionBlock<string>(
            listFilePath =>
            {
                using (var stateService = DalService.GetStateService())
                {
                    var resultsFilePath = listFilePath + ".results";
                    foreach (var state in stateService.GetStates())
                    {
                        writeReport.Post(
                        new ReportData
                        {
                            State = state,
                            ResultsFilePath = resultsFilePath
                        });
                    }
                    // This alwaus gets called
                    writeReport.Complete();
                }
            },
            new ExecutionDataflowBlockOptions
            {
                CancellationToken = _cancellationToken.Token
            });

    /*
     * Link Reporting tasks
     */
    writeReport.LinkTo(setReportStatus);
    writeReport.Completion.ContinueWith(t =>
        {
            // This only get called on first run!
            if (t.IsFaulted)
            {
                ((IDataflowBlock) setStateRecordStatus).Fault(
                    t.Exception);
                return;
            }
            setReportStatus.Complete();
        }, _cancellationToken.Token);

    /********************************************************************/
    /** Run the tasks                                                   */
    /********************************************************************/
    try
    {
        loadListFile.Post(_listFileInfo.FullName);
        loadListFile.Complete();
        await Task.WhenAll(createStateRecord.Completion);

        generateReport.Post(_listFileInfo.FullName);
        generateReport.Complete();
        await Task.WhenAll(writeReport.Completion);
    }
    catch (TaskCanceledException)
    {
        MessageBox.Show(
            "Job cancelled by user.", "Job Cancelled",
             MessageBoxButtons.OK);
        SetUiAfterProcessing("Job cancelled by user.");
    }
    catch (AggregateException aex)
    {
        MessageBox.Show(
        aex.ListExceptions(), "Task Errors", MessageBoxButtons.OK);
        SetUiAfterProcessing("Task processing error - job cancelled.");
    }
    catch (Exception ex)
    {
        MessageBox.Show(
        ex.ToString(), "Unhandled Exception", MessageBoxButtons.OK);
        SetUiAfterProcessing("Application error - job cancelled.");
    }
    finally
    {
        SetUiAfterProcessing("Job complete.");
    }
}

我尝试过重构方法并简化每个Block的内部操作,但我仍然没有更接近于确定我做错了什么 - 任何帮助都会非常感激。谢谢。

0 个答案:

没有答案