使用IProgress <t> </t>从后台线程报告

时间:2013-02-08 11:06:39

标签: c# multithreading .net-4.5 async-await progress

全部,我使用.NET4.5下的async / await关键字执行了一项昂贵的任务。我通过Progress<T>类从后台线程报告进度。

我传入IProgress<T>的对象作为类型ProgressInfo,我将其创建为单例类,以避免在运行期间多次创建和处理此类对象的开销。该课程是

public class ProgressInfo : IDisposable
{
    public static ProgressInfo instance = null;
    public WorkbookProgressInfo workbookinfo { get; set; }
    public string progressMessage { get; set; }
    public int progressPercentage { get; set; }

    // Default constructor which has a few overloads 
    // for the class members above.
    protected ProgressInfo()
    {
    }
    ...

    // The default instance creator for the class. 
    // This also has overloads to allow changes to the 
    // class variables.
    public static ProgressInfo Instance()
    {
        if (instance == null)
            instance = new ProgressInfo();
        return instance;
    }
    ...
}

我通过方法ReportProgress报告进度,并将IProgress<ProgressInfo>设置为

IProgress<CostEngine.ProgressInfo> progressIndicator =
    new Progress<CostEngine.ProgressInfo>(ReportProgress);

来自后台线程的报告通常使用全局ProgressInfo progressInfo和全局IProgress<ProgressInfo> progressIndicator来完成

...
progressInfo = new ProgressInfo.Instance(workbookinfo, message, n);
progressIndicator.Report(progressInfo);
...

问题是,对于运行较小并且执行速度很快的ProgressInfo传递给ReportProgress的对象在ReportProgress执行时发生了变化,所以我测试了

if (progressInfo.workbookinfo != null)
{
    // Do stuff <- here progressInfo.workbookinfo is changing to null!
}

如何在保持报告进度最低费用的同时避免此问题?

感谢您的时间。

1 个答案:

答案 0 :(得分:4)

您正在尝试优化应用程序的错误部分。

几千个对象对于应用程序来说都不算什么。最有可能创建它们不会是应用程序中的性能问题。但是,可能成为问题的是UI的更新。如果在短时间内发生了数千个进度报告,您将不断更新UI。更新UI会花费时间,所以如果你遇到瓶颈,它就会在这里。

这里的正确方法是仅报告您需要报告的内容 例如,如果您发生了60,000次迭代 - 比方说 - 一分钟并报告这些迭代中的每一次迭代,您将尝试每毫秒更新UI 。 你的进度条真的需要 1000 FPS 吗?我对此表示怀疑 每秒只报告一次是非常好的。但是,每秒报告会产生自己的开销。

我在申请时所做的是在百分比发生变化时立即报告 无论您实际拥有多少次迭代,这将导致最多100个报告 在上面的例子中,我将报告每600次迭代。

为了简化这一点,我实际创建了一个名为ProgressReporter的类 在它的构造函数中,它需要一个工厂委托来创建ProgressInfo对象和迭代总数 它提供了您在当前迭代中传递的ReportProgress方法 该类在内部存储先前报告的百分比,并在调用此方法时计算新百分比。只有在不同的情况下,它才会使用工厂代理创建新的ProgressInfo并在Report实例上调用IProgress<T>

顺便说一句:如果您的后台操作不需要几分钟而是几小时,您可以将其更改为在百分比更改时报告,但在百分比的第一个或第二个小数更改时报告。 这里的要点是:查找一定数量的报告,每隔几秒就会给用户一次反馈。