gpt4 book ai didi

c# - 使用 IProgress.Report() 报告进度时,控制台消息的显示顺序不正确

转载 作者:太空狗 更新时间:2023-10-29 18:19:57 25 4
gpt4 key购买 nike

我注意到以下行为。由 IProgress 填充时,控制台输出消息出现在错误的文件夹中。

var recounter = new IdRecounter(filePath, new Progress<string>(Console.WriteLine));
recounter.RecalculateIds();

我正在努力提高我的封装、可重用性和设计技能。所以,我有一个名为 IdRecounter 的类。我现在想在控制台应用程序中使用它,但稍后可能会在 WPF 应用程序或其他应用程序中使用它。

因此,我希望类(class)完全不知道它的环境 - 但同时我想报告“实时” Action 的进度 - 因此,我使用 IProgress 类型,这将允许我将东西放入控制台,或进入日志文件,或更新状态标签属性等。(如果您不是这样做的,请告诉我)

因此,我注意到它倾向于以错误的顺序将消息抛出到控制台,例如加工文件1
加工文件4
加工文件5
加工文件3
全部完成!
处理文件2

当我将 IProgress (MyProgress.Report()) 与 Console.WriteLine() 切换时,它按预期工作。
这是什么原因,如何控制?

谢谢

最佳答案

Progress<T> 类使用创建它的线程的当前同步上下文来为其 ProgressChanged 调用事件处理程序事件。

在控制台应用程序中,默认同步上下文使用线程池来调用委托(delegate),而不是将它们编码回检索上下文的线程。这意味着每次更新进度时,可能会在不同的线程中调用事件处理程序(尤其是如果进度更新快速连续发生时)。

由于线程的调度方式,无法保证一个线程池 worker 在另一个线程池 worker 实际运行它的任务之前分配了一个任务,然后另一个线程池 worker 运行它的任务。特别是对于相对简单的任务(例如发出进度消息),很容易出现后来排队的任务实际上在较早排队的任务之前完成的情况。

如果您希望保证进度更新消息按顺序显示,则需要使用不同的机制。例如,您可以使用 BlockingCollection<T> 设置生产者/消费者,其中有一个线程使用由报告进度的操作排队(生成)的消息。或者,当然,您可以直接调用 Console.WriteLine()直接(正如您已经验证的那样)。

请注意,这并不意味着您需要放弃使用 IProgress<T> 的想法.这只是意味着您需要提供自己的实现,而不是使用 Progress<T>类,至少在控制台场景中。例如:

class ConsoleProgress : IProgress<string>
{
public void ReportProgress(string text)
{
Console.WriteLine(text);
}
}

例如,这将允许您保留 IProgress<T> IdRecounter() 中的抽象类,将该类型与 UI 上下文解耦。它可以重用于控制台程序以及任何 GUI API 程序,例如 Winforms、WPF、Winrt 等。


底线:Progress<T>IProgress<T> 的一个非常有用的实现当您需要抽象 GUI 程序中所需的跨线程、同步上下文相关操作时。它将在控制台程序中工作,但因为在这种情况下它将使用线程池,所以您可能无法获得确定性排序的输出,至少在不包含与 ProgressChanged 的额外同步的情况下是这样的。事件处理程序。

关于c# - 使用 IProgress.Report() 报告进度时,控制台消息的显示顺序不正确,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33699053/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com