Multiencadeamento em C # com tarefas

o programação de computadores O termo "thread" é ​​uma abreviação de thread de execução, no qual um processador segue um caminho especificado no seu código. O conceito de seguir mais de um segmento de cada vez introduz o assunto de multitarefa e multithreading.

Um aplicativo possui um ou mais processos. Pense em um processo como um programa em execução no seu computador. Agora cada processo possui um ou mais encadeamentos. Um aplicativo de jogo pode ter um encadeamento para carregar recursos do disco, outro para fazer IA e outro para executar o jogo como um servidor.

No .NET / Windows, o sistema operacional aloca tempo do processador para um encadeamento. Cada encadeamento controla os manipuladores de exceção e a prioridade com que é executado e tem um local para salvar o contexto do encadeamento até que seja executado. O contexto do encadeamento é a informação que o encadeamento precisa retomar.

Tarefas múltiplas com threads

Os threads ocupam um pouco de memória e a criação deles leva um pouco de tempo; portanto, geralmente, você não deseja usar muitos. Lembre-se, eles competem pelo tempo do processador. Se o seu computador tiver várias CPUs, o Windows ou .NET poderá executar cada thread em uma CPU diferente, mas se Como vários threads são executados na mesma CPU, apenas um pode estar ativo por vez e a troca de threads leva Tempo.

instagram viewer

A CPU executa um thread para alguns milhões de instruções e depois muda para outro thread. Todos os registros da CPU, o ponto de execução do programa atual e a pilha precisam ser salvos em algum lugar para o primeiro encadeamento e depois restaurados em outro lugar para o próximo encadeamento.

Criando um Thread

No espaço para nome Sistema. Rosqueamento, você encontrará o tipo de thread. O encadeamento do construtor (ThreadStart) cria uma instância de um thread. No entanto, em recentes C # código, é mais provável que passe uma expressão lambda que chama o método com qualquer parâmetro.

Se você não tiver certeza sobre expressões lambda, pode valer a pena conferir o LINQ.

Aqui está um exemplo de um segmento que é criado e iniciado:

using System;
usando o sistema. Rosqueamento;
namespace ex1
{
Programa de aula
{
estático público Write1 ()
{
Console. Escreva ('1');
Fio. Sono (500);
}
static void Main (string [] args)
{
var tarefa = novo segmento (Write1);
tarefa. Start ();
para (var i = 0; i <10; i ++)
{
Console. Write ('0');
Console. Escrever (tarefa. Está vivo? 'DE ANÚNCIOS') ;
Fio. Sono (150);
}
Console. Chave de leitura() ;
}
}
}

Todo este exemplo é escrever "1" no console. O thread principal grava um "0" no console 10 vezes, cada vez seguido de um "A" ou "D", dependendo se o outro thread ainda está ativo ou morto.

O outro thread é executado apenas uma vez e grava um "1". Após o atraso de meio segundo no segmento Write1 (), o segmento termina e a tarefa. IsAlive no loop principal agora retorna "D."

Pool de threads e biblioteca paralela de tarefas

Em vez de criar seu próprio encadeamento, a menos que você realmente precise fazer isso, use um Pool de Encadeamentos. Do .NET 4.0, temos acesso à Task Parallel Library (TPL). Como no exemplo anterior, novamente precisamos de um pouco de LINQ e, sim, são todas expressões lambda.

Tarefas usa o Grupo de discussão nos bastidores, mas faça melhor uso das linhas, dependendo do número em uso.

O objeto principal no TPL é uma tarefa. Esta é uma classe que representa uma operação assíncrona. A maneira mais comum de começar a rodar é com a tarefa. Fábrica. Iniciar como em:

Tarefa. Fábrica. StartNew (() => DoSomething ());

Onde DoSomething () é o método que é executado. É possível criar uma tarefa e não executá-la imediatamente. Nesse caso, basta usar a tarefa assim:

var t = nova tarefa (() => console. WriteLine ("Olá"));
...
t. Começar();

Isso não inicia o thread até que o .Start () seja chamado. No exemplo abaixo, há cinco tarefas.

using System;
usando o sistema. Rosqueamento;
usando o sistema. Rosqueamento. Tarefas;
namespace ex1
{
Programa de aula
{
Write1 vazio estático público (int i)
{
Console. Escreva (i);
Fio. Sono (50);
}
static void Main (string [] args)
{
para (var i = 0; i <5; i ++)
{
valor var = i;
var runningTask = Tarefa. Fábrica. StartNew (() => Write1 (valor));
}
Console. Chave de leitura() ;
}
}
}

Execute isso e você obtém os dígitos de 0 a 4 de saída em alguma ordem aleatória, como 03214. Isso ocorre porque a ordem de execução da tarefa é determinada pelo .NET.

Você pode estar se perguntando por que o valor var = i é necessário. Tente removê-lo e chame Write (i), e você verá algo inesperado como 55555. Por que é isso? É porque a tarefa mostra o valor de i no momento em que a tarefa é executada, não quando a tarefa foi criada. Criando um novo variável cada vez no loop, cada um dos cinco valores é armazenado e selecionado corretamente.

instagram story viewer