Resumo : neste tutorial, você aprenderá como usar a Thread
classe C# para desenvolver programas multithread.
Introdução à classe Thread C#
Começaremos criando um programa simples:
using System.Diagnostics;
using static System.Console;
static void DoWork()
{
WriteLine("Doing the work...");
Thread.Sleep(1000);
WriteLine("done");
}
var watch = Stopwatch.StartNew();
DoWork();
DoWork();
watch.Stop();
WriteLine($"It took {watch.Elapsed.Seconds} second(s) to complete.");
Linguagem de código: C# ( cs )
Saída:
Doing the work...
done
Doing the work...
done
It took 2 second(s) to complete.
Linguagem de código: C# ( cs )
Como funciona.
Primeiro, defina o DoWork()
método que leva um segundo para ser executado. O DoWork()
método usa o Sleep()
método estático da Thread
classe para atrasar um segundo.
Segundo, use o Stopwatch
objeto para medir o tempo de execução do programa. O Startnew()
método da Stopwatch
classe inicializa um Stopwatch
objeto, redefine o tempo decorrido para zero e começa a medir o tempo.
Terceiro, chame o DoWork()
método duas vezes.
Por fim, pare de medir o tempo decorrido e imprima o tempo que levou para ser executado.
Como cada DoWork()
método leva um segundo para ser concluído, todo o programa leva cerca de 2 segundos, o que é esperado.
Usando a classe Thread C#
Para tornar o programa acima multithread, você usa a Thread
classe. As etapas para usar a Thread
classe são as seguintes:
Primeiro, crie uma nova instância da Thread
classe e passe um método para seu construtor:
var t = new Thread(method);
Linguagem de código: C# ( cs )
Segundo, chame o Start()
método para iniciar a execução do thread:
t.Start()
Linguagem de código: C# ( cs )
Terceiro, chame o Join()
método para aguardar a conclusão do thread:
t.Join()
Linguagem de código: C# ( cs )
O exemplo a seguir mostra como usar a Thread
classe para criar um programa multithread:
using System.Diagnostics;
using static System.Console;
static void DoWork()
{
WriteLine("Doing the work...");
Thread.Sleep(1000);
WriteLine("done");
}
var watch = Stopwatch.StartNew();
var t1 = new Thread(DoWork);
var t2 = new Thread(DoWork);
// start both threads
t1.Start();
t2.Start();
// wait for both threads completed
t1.Join();
t2.Join();
watch.Stop();
WriteLine($"It took {watch.Elapsed.Seconds} second(s) to complete.");
Linguagem de código: C# ( cs )
Saída:
Doing the work...
Doing the work...
done
done
It took 1 second(s) to complete.
Linguagem de código: C# ( cs )
Neste exemplo, o programa levou apenas um segundo para ser concluído, embora chame o DoWork()
método duas vezes. Ou seja, sua velocidade é o dobro em comparação ao programa que utiliza thread única.
Passando argumentos para os threads
Para passar argumentos para threads, você pode:
- Primeiro, defina um parâmetro com o tipo object no método que será executado pela thread.
- Segundo, passe o argumento para o
Start()
método.
Por exemplo:
using System.Diagnostics;
using static System.Console;
static void DoWork(object? arg)
{
if (arg == null)
{
return;
}
string message = (string)arg;
Thread.Sleep(1000);
WriteLine(message);
}
var watch = Stopwatch.StartNew();
var t1 = new Thread(DoWork);
var t2 = new Thread(DoWork);
// start both threads
t1.Start("Hi");
t2.Start("Bye");
// wait for both threads completed
t1.Join();
t2.Join();
watch.Stop();
WriteLine($"It took {watch.Elapsed.Seconds} second(s) to complete.");
Linguagem de código: C# ( cs )
Saída:
Hi
Bye
It took 1 second(s) to complete.
Linguagem de código: C# ( cs )
Alternativamente, você pode passar uma expressão lambda com argumentos para o Thread
construtor assim:
using System.Diagnostics;
using static System.Console;
static void DoWork(string message)
{
Thread.Sleep(1000);
WriteLine(message);
}
var watch = Stopwatch.StartNew();
var t1 = new Thread(() => DoWork("Hi"));
var t2 = new Thread(() => DoWork("Bye"));
// start both threads
t1.Start();
t2.Start();
// wait for both threads completed
t1.Join();
t2.Join();
watch.Stop();
WriteLine($"It took {watch.Elapsed.Seconds} second(s) to complete.");
Linguagem de código: C# ( cs )
Saída:
Hi
Bye
It took 1 second(s) to complete.
Linguagem de código: C# ( cs )
Usar uma expressão lambda é a forma preferida de passar argumentos para o thread, pois o método não precisa converter o objeto para o tipo correto antes de processá-lo.
Usos práticos de multithreading C#
O programa a seguir verifica uma lista de sites e exibe seus códigos de status HTTP correspondentes:
using System.Diagnostics;
using static System.Console;
static void CheckHttpStatus(string url)
{
HttpClient client = new();
var response = client.GetAsync(url).Result;
WriteLine($"The HTTP status code of {url} is {response.StatusCode}");
}
List<string> urls = new(){
"https://www.google.com/",
"https://www.duckduckgo.com/",
"https://www.yahoo.com/",
};
var watch = Stopwatch.StartNew();
urls.ForEach(url => CheckHttpStatus(url));
watch.Stop();
WriteLine($"It took {watch.Elapsed.Seconds} second(s) to complete.");
Linguagem de código: C# ( cs )
Saída:
The HTTP status code of https://www.google.com/ is OK
The HTTP status code of https://www.duckduckgo.com/ is OK
The HTTP status code of https://www.yahoo.com/ is OK
It took 3 second(s) to complete.
Linguagem de código: C# ( cs )
Como funciona.
Primeiro, defina um método estático CheckHttpStatus()
que use o HttpClient
objeto para obter o código de status HTTP de uma URL e exibir seu resultado:
static void CheckHttpStatus(string url)
{
HttpClient client = new();
var response = client.GetAsync(url).Result;
WriteLine($"The HTTP status code of {url} is {response.StatusCode}");
}
Linguagem de código: C# ( cs )
Segundo, defina uma lista de itens URLs
para verificar:
List<string> urls = new(){
"https://www.google.com/",
"https://www.duckduckgo.com/",
"https://www.yahoo.com/",
};
Linguagem de código: C# ( cs )
Terceiro, passe cada entrada da URLs
lista para o CheckHttpStatus()
método. Além disso, envolva as chamadas de método dentro de um bloco que usa Stopwatch
para medir o tempo de execução:
var watch = Stopwatch.StartNew();
urls.ForEach(url => CheckHttpStatus(url));
watch.Stop();
WriteLine($"It took {watch.Elapsed.Seconds} second(s) to complete.");
Linguagem de código: C# ( cs )
Já que o programa trata de solicitações de rede. É ideal para utilizar multithreading para melhorar o desempenho.
O programa a seguir exibe o código de status HTTP de uma lista de URLs
mas usa multithreading:
using System;
using System.Diagnostics;
using static System.Console;
static void CheckHttpStatus(string url)
{
HttpClient client = new();
var response = client.GetAsync(url).Result;
WriteLine($"The HTTP status code of {url} is {response.StatusCode}");
}
List<string> urls = new(){
"https://www.google.com/",
"https://www.duckduckgo.com/",
"https://www.yahoo.com/",
};
List<Thread> threads = new();
urls.ForEach(url => threads.Add(new Thread(() => CheckHttpStatus(url))));
var watch = Stopwatch.StartNew();
// start the threads
threads.ForEach(thread=> thread.Start());
// wait for all threads to complete
threads.ForEach(thread => thread.Join());
watch.Stop();
WriteLine($"It took {watch.Elapsed.Seconds} second(s) to complete.");
Linguagem de código: C# ( cs )
Saída:
The HTTP status code of https://www.google.com/ is OK
The HTTP status code of https://www.duckduckgo.com/ is OK
The HTTP status code of https://www.yahoo.com/ is OK
It took 2 second(s) to complete.
Linguagem de código: C# ( cs )
Resumo
- Use a
Thread
classe para criar um novo tópico. - Chame o
Start()
método para iniciar a execução do thread. - Chame o
Join()
método para aguardar a conclusão do thread. - Use expressões lambda para passar argumentos para threads.