Support of progress reporting and incremental resu

2020-02-23 08:06发布

问题:

I know that Task Parallel Library is still in Beta and there are likely to be less resources available but from whatever I have read, library gives very special treatment to task scheduling, exception handling and cancellation.

But I don't find any references to progress reporting and sending incremental results from tasks. These 2 things seem too important to ignore. Can you throw some light on how to handle these in Task Parallel Library or refer some articles which explains them?

回答1:

This example updates a progress bar:

using System;   
using System.Threading;   
using System.Threading.Tasks;   
using System.Windows.Forms;   

class SimpleProgressBar : Form   
{   
    [STAThread]   
    static void Main(string[] args)   
    {   
        Application.EnableVisualStyles();   
        Application.Run(new SimpleProgressBar());   
    }   

    protected override void OnLoad(EventArgs e)   
    {   
        base.OnLoad(e);   

        int iterations = 100;   

        ProgressBar pb = new ProgressBar();   
        pb.Maximum = iterations;   
        pb.Dock = DockStyle.Fill;   
        Controls.Add(pb);   

        Task.ContinueWith(delegate   
        {   
            Parallel.For(0, iterations, i =>  
            {   
                Thread.SpinWait(50000000); // do work here   
                BeginInvoke((Action)delegate { pb.Value++; });   
            });   
        });   
    }   
}  

Updating a progress bar from inside a Parallel.For



回答2:

This is one of my top search result and still no example for progress in Task Parallel Library right here...

Today I just came across TPL because I want to develop new multithreaded application but without using BackgroundWorker (because I read somewhere about task with nice code before)

I compile the example from @Stephen Cleary answer, his link quite complicated for to look for progress, and some other websites.

This is the very simple example to how to do Progress and Completed with UI thread safe way:

        TaskScheduler currentTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
        Task<string>.Factory.StartNew(() =>
        {
            // loop for about 10s with 10ms step
            for (int i = 0; i < 1000; i++)
            {
                Thread.Sleep(10);
                Task.Factory.StartNew(() =>
                {
                    // this is a task created each time you want to update to the UI thread.
                    this.Text = i.ToString();
                }, CancellationToken.None, TaskCreationOptions.None, currentTaskScheduler);
            }
            return "Finished!";
        })
        .ContinueWith(t =>
        {
            // this is a new task will be run after the main task complete!
            this.Text += " " + t.Result;
        }, currentTaskScheduler);

The code will display 1 to 1000 within 10s and then append a " Finish!" string in the windows form title bar. You can see that the TaskScheduler is the tricky way to create UI thread safe update because I think the task scheduled to be run on main thread.



回答3:

There is no built-in support for this like what BackgroundWorker had.

You can use SynchronizationContext directly; there's an excellent video here: http://www.rocksolidknowledge.com/ScreenCasts.mvc/Watch?video=TasksAndThreadAffinity.wmv

The author develops two solutions in this video: one using SynchronizationContext and another using Task Continuations. For your problem, continuations will not work, but the SynchronizationContext approach would work fine.

P.S. If you're creating reusable code, then when you capture SynchronizationContext.Current, you should test for null and (if it is null) use a default-constructed SynchronizationContext instead.

UPDATE: I've posted code for this on my blog. My solution is actually based on a Task that is scheduled back to the UI thread by a TaskScheduler which uses SynchronizationContext underneath. Unlike the accepted answer, this solution will work for both WPF and Windows Forms.



回答4:

The TPL isn't particularly oriented toward UI support, you can (still) use a BackgroundWorker for that. As for sending or processing intermediate results, there are new collectionclasses (ConcurrentQueue) to support that.



回答5:

To report progress from an async task, pass an IProgress into the async method. Within the method, call Report with the progress data. The caller can decide how to handle that progress report (i.e. Ignore it, or update the UI).