The Progress<T>
class uses the current synchronization context for the thread in which it was created to invoke the event handlers for its ProgressChanged
event.
In a console application, the default synchronization context uses the thread pool to invoke delegates, rather than marshaling them back to the thread where the context is retrieved. This means that each time you update progress, the event handler may be invoked in a different thread (especially if the progress updates occur in quick succession).
Due to the way threads are scheduled, there is no guarantee that a thread pool worker assigned a task before another thread pool worker will actually run its task before that other worker runs its task. Especially for relatively simple tasks (such as emitting progress messages), it can easily be the case then that tasks enqueued later are actually completed before tasks enqueued earlier.
If you want for your progress update messages to be guaranteed to be displayed in order, you'll need to use a different mechanism. For example, you could set up a producer/consumer with BlockingCollection<T>
, where you have a single thread consuming messages that are queued (produced) by your operations that report progress. Or, of course, you could just call Console.WriteLine()
directly (as you have already verified will work).
Note that that doesn't mean you need to abandon the idea of using IProgress<T>
. It just means you would need to provide your own implementation, rather than using the Progress<T>
class, at least in the console scenario. For example:
class ConsoleProgress : IProgress<string>
{
public void ReportProgress(string text)
{
Console.WriteLine(text);
}
}
This would allow you to, for example, keep the IProgress<T>
abstraction in the IdRecounter()
class, decoupling that type from the UI context. It could be reused for a console program as well as any GUI API program, such as Winforms, WPF, Winrt, etc.
The bottom line: Progress<T>
is a very useful implementation of IProgress<T>
when you need to abstract the cross-thread, synchronization context-related operations that are needed in a GUI program. It will work in console programs, but because it will use the thread pool in that case, you may not get deterministically ordered output, at least not without including additional synchronization to the ProgressChanged
event handlers.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…