Compartilhar via


Agendadores de tarefa

Agendadores de tarefa são representados pela System.Threading.Tasks.TaskScheduler classe. O Agendador de tarefas certifica-se de que o trabalho de uma tarefa é finalmente executado. O Agendador de tarefas padrão se baseia no.NET Framework 4 ThreadPool, que fornece o roubo de trabalho para balanceamento de carga, segmento de injeção/aposentadoria para throughput máximo e o desempenho geral boa. Ele deve ser suficiente para a maioria dos cenários. Entretanto, se você precisar de funcionalidade especial, crie um Agendador personalizado e ativá-lo para tarefas específicas ou consultas. Para obter mais informações sobre como criar e usar o Agendador de tarefas personalizado, consulte Como: Criar um Agendador de tarefas que limita o grau de simultaneidade. Para obter exemplos adicionais de agendadores personalizados, consulte Amostras de extensões paralelas no site da Web de galeria de código do MSDN.

O Agendador de tarefas padrão e o ThreadPool.

O agendador padrão para usos biblioteca paralela de tarefas e PLINQ o.NET Framework ThreadPool a fila e executar o trabalho. No .NET Framework 4, o ThreadPool usa as informações fornecidas pelo System.Threading.Tasks.Task Digite o paralelismo refinado (unidades de trabalho de curta duração) eficiente suporte a tarefas em paralelo e consulta geralmente representam.

Vs de fila de ThreadPool Global.Filas locais

Como nas versões anteriores do.NET Framework, o ThreadPool mantém uma global FIFO (first in, First) funcionam a fila de threads em cada domínio de aplicativo. Sempre que um programa chama QueueUserWorkItem (ou UnsafeQueueUserWorkItem), o trabalho é colocar nessa fila compartilhada e eventualmente desenfileirado até o próximo segmento que fica disponível. No .NET Framework 4, essa fila foi aperfeiçoada para usar um algoritmo sem bloqueio semelhante a classe deConcurrentQueue . Usando essa implementação sem bloqueio, o ThreadPool gasta menos tempo quando ela filas e desenfileira itens de trabalho. Esse benefício de desempenho está disponível para todos os programas que usam o ThreadPool.

Tarefas de nível superior que são tarefas que não são criadas no contexto de outra tarefa, são colocadas na fila assim como qualquer outro item de trabalho global. No entanto, aninhados ou tarefas filho, que são criadas no contexto de outra tarefa, são tratadas de forma bastante diferente. Um filho ou uma tarefa aninhada é colocada em uma fila local que é específica para o segmento em que a tarefa pai está em execução. A tarefa de pai pode ser uma tarefa de nível superior ou também pode ser o filho de outra tarefa. Quando esse thread está pronto para trabalhar mais, ele procura primeiro na fila local. Se os itens de trabalho estiverem aguardando lá, podem ser acessados rapidamente. Filas locais são acessadas na ordem última-in, First-out (LIFO) para preservar a localidade de cache e reduzir a contenção. Para obter mais informações sobre tarefas filho e aninhadas de tarefas, consulte Aninhados de tarefas e tarefas filho.

O exemplo a seguir mostra algumas tarefas que estão agendadas em fila global e outras tarefas que estão agendadas em fila local.

Sub QueueTasks()

    ' TaskA is a top level task.
    Dim taskA = Task.Factory.StartNew(Sub()

                                          Console.WriteLine("I was enqueued on the thread pool's global queue.")

                                          ' TaskB is a nested task and TaskC is a child task. Both go to local queue.
                                          Dim taskB = New Task(Sub() Console.WriteLine("I was enqueued on the local queue."))
                                          Dim taskC = New Task(Sub() Console.WriteLine("I was enqueued on the local queue, too."),
                                                                  TaskCreationOptions.AttachedToParent)

                                          taskB.Start()
                                          taskC.Start()

                                      End Sub)
End Sub
void QueueTasks()
{
    // TaskA is a top level task.
    Task taskA = Task.Factory.StartNew( () =>
    {                
        Console.WriteLine("I was enqueued on the thread pool's global queue."); 

        // TaskB is a nested task and TaskC is a child task. Both go to local queue.
        Task taskB = new Task( ()=> Console.WriteLine("I was enqueued on the local queue."));
        Task taskC = new Task(() => Console.WriteLine("I was enqueued on the local queue, too."),
                                TaskCreationOptions.AttachedToParent);

        taskB.Start();
        taskC.Start();

    });
}

O uso de filas locais não só reduz a pressão na fila global, ele também tira proveito da localidade de dados. Freqüentemente, os itens de trabalho local fila estruturas de dados de referência que estão fisicamente próximos uns aos outros na memória. Nesses casos, os dados já estão no cache após a primeira tarefa foi executado e pode ser acessada rapidamente. Ambos plinq (Parallel linq) e o Parallel classe use aninhadas de tarefas e tarefas filho extensivamente e alcançar os aumentos de velocidade significativos por meio de filas de trabalho local.

Roubo de trabalho

O .NET Framework 4 ThreadPool também o algoritmo de um roubo de trabalho de recursos para ajudar a certificar-se de que nenhum thread está sentado ocioso enquanto outros ainda têm funciona em suas filas. Quando um thread do pool de threads está pronto para ser mais trabalho, primeiro procura no topo da sua fila local, em seguida, na fila global e em filas locais de outros segmentos. Se ele encontrar um item de trabalho na fila local de outro segmento, ele primeiro se aplica a heurística para certificar-se de que ela pode executar o trabalho com eficiência. Se puder, ele desenfileira o item de trabalho da parte inferior (em ordem FIFO). Isso reduz a contenção de cada fila local e preserva a localidade de dados. Essa arquitetura ajuda a .NET Framework 4 ThreadPool load-balance trabalhem de modo mais eficiente do que versões passadas.

Tarefas de execução demorada

Você talvez queira explicitamente impedir que uma tarefa que está sendo colocado em uma fila local. Por exemplo, você pode saber que um determinado item de trabalho será executado por um tempo relativamente longo e provavelmente bloquear todos os outros itens de trabalho na fila local. Nesse caso, você pode especificar o LongRunning opção, que fornece uma dica para o Agendador que um segmento adicional pode ser necessário para a tarefa para que ele não bloqueia o progresso de outros segmentos ou trabalhar itens na fila local. Usando esta opção, você evita a ThreadPool completamente, incluindo filas globais e locais.

Tarefa Inlining

Em alguns casos, quando uma tarefa é aguardada, ele pode ser executado sincronicamente no Thread que está realizando a operação de esperar. Isso melhora o desempenho, pois ela evita a necessidade de um segmento adicional, utilizando o Thread de existente que seria bloqueadas, caso contrário. Para evitar erros devido a reentrada, tarefa inlining só ocorre quando o destino de espera é encontrado na fila de local do segmento relevantes.

Especificando um contexto de sincronização

Você pode usar o TaskScheduler.FromCurrentSynchronizationContext método para especificar que uma tarefa deve ser agendada para ser executado em um segmento específico. Isso é útil em estruturas como, por exemplo, Windows Forms e Windows Presentation Foundation de onde o acesso aos objetos de interface do usuário geralmente é restrito ao código que está sendo executado no mesmo thread no qual o objeto de interface do usuário foi criado. Para obter mais informações, consulte Como: Agenda de trabalho em um contexto de sincronização especificado.

Consulte também

Referência

TaskScheduler

Conceitos

Biblioteca paralela de tarefas

Como: Agenda de trabalho em um contexto de sincronização especificado

Outros recursos

Como: Criar um Agendador de tarefas que limita o grau de simultaneidade

Fábricas de tarefa