Suporte ao relatório de progresso e resultados incrementais no .NET 4.0 “Biblioteca paralela de tarefas”

StackOverflow https://stackoverflow.com/questions/1535749

Pergunta

eu sei que Tarefa Biblioteca paralela ainda está na versão beta e é provável que haja menos recursos disponíveis, mas de tudo o que eu li, a biblioteca faz um tratamento muito especial para programação de tarefas, manipulação de exceção e cancelamento.

Mas não encontro nenhuma referência a Relatório de progresso e enviando resultados incrementais de tarefas. Essas duas coisas parecem importantes demais para ignorar. Você pode lançar alguma luz sobre como lidar com isso na Biblioteca paralela de tarefas ou encaminhar alguns artigos que os explica?

Foi útil?

Solução

Este exemplo atualiza uma barra de progresso:

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++; });   
            });   
        });   
    }   
}  

Atualizando uma barra de progresso de dentro de um paralelo.

Outras dicas

Este é um dos meus principais resultados de pesquisa e ainda não há exemplo para progresso em Task Parallel Library bem aqui...

Hoje acabei de me deparar com a TPL porque quero desenvolver um novo aplicativo multithread, mas sem usar BackgroundWorker (Porque eu li em algum lugar sobre tarefa com bom código antes)

Compilo o exemplo da resposta @Stephen Cleary, seu link bastante complicado para procurar progresso e alguns outros sites.

Este é o exemplo muito simples de como fazer Progresso e Concluído Com a maneira segura do tópico da interface do usuário:

        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);

O código exibirá 1 a 1000 dentro de 10s e depois anexará um "acabamento!" String na barra de título do formulário do Windows. Você pode ver que o TaskScheduler é a maneira complicada de criar uma atualização segura do tópico da interface do usuário, porque acho que a tarefa programada para ser executada no thread principal.

Não há suporte embutido para isso, como o BackgroundWorker tinha.

Você pode usar o SynchronizationContext diretamente; Há um excelente vídeo aqui: http://www.rocksolidknowledge.com/screencasts.mvc/watch?video=tasksandThreadAffinity.wmv

O autor desenvolve duas soluções neste vídeo: uma usando o SynchronizationContext e outro usando continuações de tarefas. Para o seu problema, as continuações não funcionarão, mas a abordagem da SynchronizationContext funcionaria bem.

PS Se você estiver criando código reutilizável, quando você captura a SynchronizationContext.Current, você deve testar o NULL e (se for nulo), use um synchronizationcontext construído por padrão.

ATUALIZAR: Eu publiquei código para isso no meu blog. Minha solução é realmente baseada em um Task que está agendado de volta ao tópico da interface do usuário por um TaskScheduler que usa SynchronizationContext por baixo. Ao contrário da resposta aceita, esta solução funcionará para os formulários WPF e Windows.

O TPL não está particularmente orientado para o suporte da interface do usuário, você pode (ainda) usar um trabalho de fundo para isso. Quanto ao envio ou processamento de resultados intermediários, existem novas casas de coleta (ConcurrentQueue) para apoiar isso.

Para relatar o progresso de uma tarefa assíncrona, passe um IProgress no método assíncrono. Dentro do método, ligue Relatório com os dados de progresso. O chamador pode decidir como lidar com esse relatório de progresso (ou seja, ignorá -lo ou atualizar a interface do usuário).

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top