Como Usar Async e Multithreading para Operações de Código QR em C
A digitalização de QR de um único thread bloqueia o thread de chamada durante a duração de cada decodificação de imagem.
Em um manipulador de botão WPF, isso congela a interface do usuário até que a decodificação seja concluída. Em um processamento em lote de centenas de imagens, isso deixa núcleos da CPU ociosos quando poderiam estar trabalhando em paralelo. O método ReadAsync do IronQR descarrega leituras individuais para uma tarefa aguardável, e o método padrão Read funciona com Parallel.ForEach e Task.WhenAll para processamento em lote.
Este guia demonstra como processar códigos QR de forma assíncrona, distribuir leituras em lote entre os núcleos da CPU e combinar ambos os padrões para pipelines de alto volume.
Início rápido: Processar Códigos QR Assincronamente
Carrega uma imagem e aguarda os resultados decodificados sem bloquear a thread de chamada.
-
Instale IronQR com o Gerenciador de Pacotes NuGet
PM > Install-Package IronQR -
Copie e execute este trecho de código.
using IronQr; using IronSoftware.Drawing; var input = new QrImageInput(AnyBitmap.FromFile("ticket.png")); IEnumerable<QrResult> results = await new QrReader().ReadAsync(input); Console.WriteLine(results.First().Value); -
Implante para testar em seu ambiente de produção.
Comece a usar IronQR em seu projeto hoje com uma avaliação gratuita
Fluxo de trabalho mínimo (5 etapas)
- Baixar a biblioteca C# IronQR para processamento assíncrono de códigos QR
- Use
ReadAsyncpara leituras únicas não bloqueantes. - Use
Parallel.ForEachpara processamento em lote vinculado à CPU - Combine com
SemaphoreSlimpara pipelines de concorrência limitados - Colete os resultados de
IEnumerablee imprima os valores decodificados.
Leitura assíncrona de códigos QR
ReadAsync retorna uma tarefa assíncrona, tornando-a compatível com manipuladores de eventos WPF/MAUI, ações de controladores ASP.NET ou qualquer método assíncrono. A entrada deve ser construída a partir de um bitmap de imagem; não há sobrecarga de caminho de arquivo.
O lado da escrita é síncrono e não possui variantes assíncronas. Para evitar o bloqueio da thread durante a E/S de arquivos, envolva a etapa de salvamento em File.WriteAllBytesAsync() usando os bytes brutos exportados do bitmap.
Entrada
Um crachá de evento com código QR foi escaneado e regenerado para demonstrar o padrão de leitura e gravação assíncrona.
:path=/static-assets/qr/content-code-examples/how-to/async-and-multithreading/async-read-write.cs
using IronQr;
using IronQr.Enum;
using IronSoftware.Drawing;
// --- Async read: non-blocking QR decode ---
var inputBmp = AnyBitmap.FromFile("event-badge.png");
var imageInput = new QrImageInput(inputBmp, QrScanMode.OnlyDetectionModel);
var reader = new QrReader();
IEnumerable<QrResult> results = await reader.ReadAsync(imageInput);
foreach (QrResult result in results)
{
Console.WriteLine($"[{result.QrType}] {result.Value}");
}
// --- Async-wrapped save: QrWriter.Write() and QrCode.Save() are synchronous ---
QrCode qrCode = QrWriter.Write("https://ironsoftware.com");
AnyBitmap qrImage = qrCode.Save();
// Save the bitmap bytes asynchronously (not an IronQR API — standard .NET async I/O)
byte[] pngBytes = qrImage.ExportBytes();
await File.WriteAllBytesAsync("output-qr.png", pngBytes);
Imports IronQr
Imports IronQr.Enum
Imports IronSoftware.Drawing
Imports System.IO
' --- Async read: non-blocking QR decode ---
Dim inputBmp = AnyBitmap.FromFile("event-badge.png")
Dim imageInput = New QrImageInput(inputBmp, QrScanMode.OnlyDetectionModel)
Dim reader = New QrReader()
Dim results As IEnumerable(Of QrResult) = Await reader.ReadAsync(imageInput)
For Each result As QrResult In results
Console.WriteLine($"[{result.QrType}] {result.Value}")
Next
' --- Async-wrapped save: QrWriter.Write() and QrCode.Save() are synchronous ---
Dim qrCode As QrCode = QrWriter.Write("https://ironsoftware.com")
Dim qrImage As AnyBitmap = qrCode.Save()
' Save the bitmap bytes asynchronously (not an IronQR API — standard .NET async I/O)
Dim pngBytes As Byte() = qrImage.ExportBytes()
Await File.WriteAllBytesAsync("output-qr.png", pngBytes)
Saída
O terminal exibe o tipo e o valor do QR decodificado no formato [QrType] Value e, em seguida, confirma que output-qr.png foi salvo.
QrScanMode.Auto executa tanto a detecção por aprendizado de máquina quanto uma varredura básica, preenchendo o valor decodificado e o tipo de QR Code em cada resultado. OnlyDetectionModel é mais rápido, mas retorna apenas as coordenadas da caixa delimitadora, deixando o campo de valor vazio. Use Auto sempre que o conteúdo codificado for necessário.
Processamento de códigos QR com multithreading
Para imagens que podem ser decodificadas independentemente, Parallel.ForEach distribui o trabalho entre os núcleos de CPU disponíveis. Uma instância QrReader separada por iteração é o padrão seguro, já que o IronQR não oferece nenhuma garantia explícita de segurança de thread para instâncias de leitor compartilhadas.
Entrada
Quatro das dez imagens de teste de código QR usadas na leitura em lote paralela. Cada imagem codifica um URL e é lida da pasta qr-images/ em tempo de execução.
Imagem 1 (Lote 1 de 10)
Imagem 2 (Lote 2 de 10)
Imagem 3 (Lote 3 de 10)
Imagem 4 (Lote 4 de 10)
:path=/static-assets/qr/content-code-examples/how-to/async-and-multithreading/parallel-batch.cs
using IronQr;
using IronQr.Enum;
using IronSoftware.Drawing;
using System.Collections.Concurrent;
using System.Diagnostics;
string[] files = Directory.GetFiles("qr-images/", "*.png");
var allResults = new ConcurrentBag<(string File, string Value)>();
int failCount = 0;
var sw = Stopwatch.StartNew();
Parallel.ForEach(files, new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount }, file =>
{
try
{
var input = new QrImageInput(
AnyBitmap.FromFile(file),
QrScanMode.OnlyDetectionModel);
// Per-thread QrReader instance — safe default
var results = new QrReader().Read(input);
foreach (QrResult result in results)
{
allResults.Add((Path.GetFileName(file), result.Value));
}
}
catch (Exception ex)
{
Interlocked.Increment(ref failCount);
Console.Error.WriteLine($"[ERROR] {Path.GetFileName(file)}: {ex.Message}");
}
});
sw.Stop();
Console.WriteLine($"Processed {files.Length} files in {sw.Elapsed.TotalSeconds:F1}s");
Console.WriteLine($"QR codes found: {allResults.Count} | Failures: {failCount}");
Console.WriteLine($"Throughput: {files.Length / sw.Elapsed.TotalSeconds:F1} files/sec");
Imports IronQr
Imports IronQr.Enum
Imports IronSoftware.Drawing
Imports System.Collections.Concurrent
Imports System.Diagnostics
Dim files As String() = Directory.GetFiles("qr-images/", "*.png")
Dim allResults As New ConcurrentBag(Of (File As String, Value As String))()
Dim failCount As Integer = 0
Dim sw As Stopwatch = Stopwatch.StartNew()
Parallel.ForEach(files, New ParallelOptions With {.MaxDegreeOfParallelism = Environment.ProcessorCount}, Sub(file)
Try
Dim input As New QrImageInput(AnyBitmap.FromFile(file), QrScanMode.OnlyDetectionModel)
' Per-thread QrReader instance — safe default
Dim results = New QrReader().Read(input)
For Each result As QrResult In results
allResults.Add((Path.GetFileName(file), result.Value))
Next
Catch ex As Exception
Interlocked.Increment(failCount)
Console.Error.WriteLine($"[ERROR] {Path.GetFileName(file)}: {ex.Message}")
End Try
End Sub)
sw.Stop()
Console.WriteLine($"Processed {files.Length} files in {sw.Elapsed.TotalSeconds:F1}s")
Console.WriteLine($"QR codes found: {allResults.Count} | Failures: {failCount}")
Console.WriteLine($"Throughput: {files.Length / sw.Elapsed.TotalSeconds:F1} files/sec")
Saída
O console exibe um resumo do lote, incluindo o número de arquivos processados, o tempo de processamento, os códigos QR encontrados, quaisquer falhas e a taxa de transferência. Em seguida, lista cada nome de arquivo com seu URL decodificado.
Baixe todas as 10 imagens de teste para entrada de código QR em lote (batch-qr-images.zip).
ConcurrentBag<t> reúne resultados de todas as threads sem exigir bloqueios. Um contador thread-safe rastreia falhas, e o uso de try-catch para cada arquivo garante que uma imagem defeituosa não interrompa todo o lote. Essa abordagem segue o padrão de isolamento de erros descrito no guia de tratamento de erros .
Defina MaxDegreeOfParallelism para Environment.ProcessorCount para alinhar com o número de núcleos da CPU. O uso de threads adicionais aumenta a sobrecarga e não melhora o desempenho, especialmente para modelos de aprendizado de máquina que exigem muito da CPU.
Combinando processamento assíncrono e paralelo
Para pipelines de alto volume, combine SemaphoreSlim com Task.WhenAll para limitar a concorrência. Ao contrário de Parallel.ForEach, este padrão mantém a E/S não bloqueante, controlando ao mesmo tempo quantas decodificações são executadas simultaneamente, evitando a saturação do pool de threads sob grandes cargas de trabalho.
Entrada
Quatro das vinte imagens de teste de código QR processadas pelo pipeline concorrente. Cada imagem codifica um URL e é decodificada em paralelo usando concorrência limitada via SemaphoreSlim.
Imagem 1 (Tubulação 1 de 20)
Imagem 2 (Tubo 2 de 20)
Imagem 3 (Tubulação 3 de 20)
Imagem 4 (Tubulação 4 de 20)
:path=/static-assets/qr/content-code-examples/how-to/async-and-multithreading/semaphore-pipeline.cs
using IronQr;
using IronQr.Enum;
using IronSoftware.Drawing;
using System.Collections.Concurrent;
using System.Diagnostics;
string[] files = Directory.GetFiles("high-volume/", "*.png");
var results = new ConcurrentBag<(string File, string Value)>();
int maxConcurrency = Environment.ProcessorCount;
using var semaphore = new SemaphoreSlim(maxConcurrency);
var sw = Stopwatch.StartNew();
var tasks = files.Select(async file =>
{
await semaphore.WaitAsync();
try
{
var bmp = AnyBitmap.FromFile(file);
// OnlyDetectionModel: fastest per-image — critical at scale
var input = new QrImageInput(bmp, QrScanMode.OnlyDetectionModel);
var qrResults = await new QrReader().ReadAsync(input);
foreach (var qr in qrResults)
{
results.Add((Path.GetFileName(file), qr.Value));
}
}
catch (Exception ex)
{
Console.Error.WriteLine($"{{\"file\":\"{Path.GetFileName(file)}\",\"error\":\"{ex.Message}\"}}");
}
finally
{
semaphore.Release();
}
});
await Task.WhenAll(tasks);
sw.Stop();
Console.WriteLine($"Pipeline complete: {results.Count} QR codes from {files.Length} files in {sw.Elapsed.TotalSeconds:F1}s");
Imports IronQr
Imports IronQr.Enum
Imports IronSoftware.Drawing
Imports System.Collections.Concurrent
Imports System.Diagnostics
Module Program
Sub Main()
Dim files As String() = Directory.GetFiles("high-volume/", "*.png")
Dim results As New ConcurrentBag(Of (File As String, Value As String))()
Dim maxConcurrency As Integer = Environment.ProcessorCount
Using semaphore As New SemaphoreSlim(maxConcurrency)
Dim sw As Stopwatch = Stopwatch.StartNew()
Dim tasks = files.Select(Function(file) Task.Run(Async Function()
Await semaphore.WaitAsync()
Try
Dim bmp = AnyBitmap.FromFile(file)
' OnlyDetectionModel: fastest per-image — critical at scale
Dim input As New QrImageInput(bmp, QrScanMode.OnlyDetectionModel)
Dim qrResults = Await (New QrReader()).ReadAsync(input)
For Each qr In qrResults
results.Add((Path.GetFileName(file), qr.Value))
Next
Catch ex As Exception
Console.Error.WriteLine($"{{""file"":""{Path.GetFileName(file)}"",""error"":""{ex.Message}""}}")
Finally
semaphore.Release()
End Try
End Function))
Task.WhenAll(tasks).Wait()
sw.Stop()
Console.WriteLine($"Pipeline complete: {results.Count} QR codes from {files.Length} files in {sw.Elapsed.TotalSeconds:F1}s")
End Using
End Sub
End Module
Saída
O console exibe um resumo quando o pipeline termina: total de códigos QR decodificados, número de arquivos de origem e tempo decorrido, seguido por cada nome de arquivo e seu URL decodificado.
Baixe todas as 20 imagens de entrada de código QR do pipeline de teste (high-volume-qr-images.zip).
Ajuste o limite de semáforos à quantidade de núcleos disponíveis para obter a melhor taxa de transferência ou reduza-o quando a pressão sobre a memória for uma preocupação com imagens grandes.
Leitura complementar
- Exemplo de varredura ML : comparação do modo de varredura com exemplos de código.
- Como ler códigos QR : estrutura de entrada e padrões básicos de leitura.
- Tutorial de Gerador de Código QR : geração com estilização.
- Referência da API do QrReader : assinaturas de métodos e observações.
- Referência da API QrWriter : todas as sobrecargas de escrita.
- Guia de tratamento de erros : isolamento de erros por arquivo e padrões de registro.
Visualizar opções de licenciamento quando o pipeline estiver pronto para produção.
Perguntas frequentes
O que é processamento assíncrono de código QR em C#?
O processamento assíncrono de código QR em C# permite realizar operações de código QR sem bloquear o thread principal, utilizando recursos como o método ReadAsync do IronQR para melhorar o desempenho e a capacidade de resposta.
Como o multithreading pode melhorar o processamento de códigos QR?
O multithreading pode melhorar significativamente o processamento de códigos QR ao permitir que várias operações sejam executadas simultaneamente, facilitando tempos de processamento mais rápidos e eficiência aprimorada de aplicativos através do uso do IronQR.
O que é o método ReadAsync no IronQR?
O método ReadAsync no IronQR permite a leitura assíncrona de códigos QR, permitindo que seu aplicativo C# manipule dados de código QR sem atrasar outras tarefas.
Como o Parallel.ForEach ajuda no processamento de código QR?
O Parallel.ForEach permite o processamento simultâneo de múltiplos códigos QR distribuindo tarefas por múltiplos threads, que podem ser eficientemente utilizados com o IronQR para acelerar as operações de código QR.
Qual é o papel do SemaphoreSlim nas operações de código QR?
SemaphoreSlim é usado para limitar o número de tarefas simultâneas, ajudando a gerenciar recursos de forma eficaz durante o processamento paralelo de códigos QR com o IronQR.
O IronQR pode ser usado para processar códigos QR em um pipeline delimitado?
Sim, o IronQR pode ser usado para processar códigos QR em um pipeline delimitado, usando construções como SemaphoreSlim para controlar a simultaneidade e a alocação de recursos de forma eficaz.
Quais são os benefícios de usar o IronQR para operações assíncronas de código QR?
O uso do IronQR para operações assíncronas de código QR melhora a capacidade de resposta do aplicativo, reduz o bloqueio no thread principal e permite o manuseio eficiente de grandes volumes de dados de códigos QR.
É possível executar operações de código QR em paralelo usando o IronQR?
Sim, o IronQR suporta o processamento paralelo de operações de código QR, permitindo que você aproveite as capacidades de multithreading em C# para um manuseio de códigos QR mais rápido e eficiente.
Como o IronQR aprimora o processamento de códigos QR em aplicativos C#?
O IronQR aprimora o processamento de códigos QR ao fornecer capacidades robustas de processamento assíncrono e multithreading, reduzindo os tempos de processamento e melhorando a escalabilidade dos aplicativos C#.
Quais recursos do C# complementam o uso do IronQR para processamento de códigos QR?
Recursos do C#, como async/await, Parallel.ForEach e SemaphoreSlim, complementam o IronQR, fornecendo uma estrutura para processamento eficiente e de alto desempenho de códigos QR.

