Comment utiliser Async et le multithreading pour les opérations de QR Code en C
Le scan QR à un seul thread bloque le thread appelant pendant la durée de chaque décodage d'image.
Dans un gestionnaire de bouton WPF, cela fige l'interface utilisateur jusqu'à la fin du décodage. Lors du traitement par lots de centaines d'images, les cœurs du processeur restent inactifs alors qu'ils pourraient fonctionner en parallèle. La méthode ReadAsync d'IronQR déleste les lectures individuelles vers une tâche en attente, et la méthode standard Read fonctionne avec Parallel.ForEach et Task.WhenAll pour le débit par lots.
Ce guide explique comment traiter les codes QR de manière asynchrone, répartir les lectures par lots sur les cœurs du processeur et combiner les deux modèles pour les pipelines à haut volume.
Démarrage rapide : Traiter des QR Codes de manière asynchrone
Charger une image et attendre les résultats décodés sans bloquer le thread appelant.
-
Installez IronQR avec le Gestionnaire de Packages NuGet
PM > Install-Package IronQR -
Copiez et exécutez cet extrait de code.
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); -
Déployez pour tester sur votre environnement de production.
Commencez à utiliser IronQR dans votre projet dès aujourd'hui avec un essai gratuit
Flux de travail minimal (5 étapes)
- Téléchargez la bibliothèque IronQR C# pour le traitement QR asynchrone
- Utilisez
ReadAsyncpour les lectures uniques non bloquantes. - Utilisez
Parallel.ForEachpour le traitement par lot lié au CPU - Combinez avec
SemaphoreSlimpour des pipelines de concurrence limitée - Collectez les résultats de
IEnumerableet affichez les valeurs décodées
Lecture asynchrone des codes QR
ReadAsync renvoie une tâche pouvant être attendue, ce qui la rend compatible avec les gestionnaires d'événements WPF/MAUI, les actions de contrôleur ASP.NET ou toute méthode asynchrone. L'entrée doit être construite à partir d'une image bitmap ; il n'y a pas de surcharge de chemin de fichier.
L'écriture est synchrone et ne comporte aucune variante asynchrone. Pour éviter de bloquer le thread pendant les opérations d'E/S de fichiers, encapsulez l'étape d'enregistrement dans File.WriteAllBytesAsync() en utilisant les octets bruts exportés depuis le bitmap.
Entrée
Un badge d'événement à code QR scanné et régénéré pour illustrer le modèle de lecture et d'écriture asynchrone.
: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)
Sortie
Le terminal affiche le type et la valeur du QR décodé au format [QrType] Value, puis confirme que output-qr.png a été enregistré.
QrScanMode.Auto exécute à la fois une détection ML et un passage de scan de base, en renseignant la valeur décodée et le type de QR dans chaque résultat. OnlyDetectionModel est plus rapide mais ne renvoie que les coordonnées du cadre de sélection, laissant le champ de valeur vide. Utilisez Auto chaque fois que le contenu codé est nécessaire.
Traitement des codes QR avec multithreading
Pour les images pouvant être décodées indépendamment, Parallel.ForEach répartit la charge de travail entre les cœurs de processeur disponibles. Une instance QrReader distincte par itération est la valeur par défaut sûre, car IronQR n'offre aucune garantie explicite de sécurité des threads pour les instances de lecteur partagées.
Entrée
Quatre des dix images de test de code QR utilisées dans le scan par lots parallèle. Chaque image contient une URL et est lue à partir du dossier qr-images/ lors de l'exécution.
Image 1 (Lot 1 sur 10)
Image 2 (Lot 2 sur 10)
Image 3 (Lot 3 sur 10)
Image 4 (Lot 4 sur 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")
Sortie
La console affiche un résumé du traitement par lots, incluant le nombre de fichiers traités, le temps de traitement, les codes QR trouvés, les éventuelles erreurs et le débit. Il liste ensuite chaque nom de fichier avec son URL décodée.
Téléchargez les 10 images d'entrée de code QR du lot de test (batch-qr-images.zip).
ConcurrentBag<t> rassemble les résultats de tous les threads sans nécessiter de verrous. Un compteur thread-safe suit les échecs, et l'utilisation de try-catch pour chaque fichier garantit qu'une image défectueuse n'interrompt pas le traitement par lots entier. Cette approche suit le modèle d'isolation des erreurs décrit dans le guide pratique de gestion des erreurs .
Remplacer MaxDegreeOfParallelism par Environment.ProcessorCount pour s'aligner sur le nombre de cœurs de processeur. L'utilisation de threads supplémentaires augmente la surcharge et n'améliore pas les performances, en particulier pour les modèles d'apprentissage automatique gourmands en ressources CPU.
Combinaison du traitement asynchrone et parallèle
Pour les pipelines à haut débit, associez SemaphoreSlim à Task.WhenAll pour limiter la concurrence. Contrairement à Parallel.ForEach, ce modèle maintient les E/S non bloquantes tout en contrôlant le nombre de décodages exécutés simultanément, ce qui empêche la saturation du pool de threads en cas de charges de travail importantes.
Entrée
Quatre des vingt images de test de codes QR traitées par le pipeline concurrent. Chaque image encode une URL et est décodée en parallèle à l'aide d'une concurrence limitée via SemaphoreSlim.
Image 1 (Pipeline 1 sur 20)
Image 2 (Pipeline 2 sur 20)
Image 3 (Pipeline 3 sur 20)
Image 4 (Pipeline 4 sur 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
Sortie
La console affiche un résumé une fois le pipeline terminé : nombre total de codes QR décodés, nombre de fichiers sources et temps écoulé, suivis du nom de chaque fichier et de son URL décodée.
Téléchargez les 20 images d'entrée de code QR du pipeline de test (high-volume-qr-images.zip).
Adaptez la limite des sémaphores au nombre de cœurs disponibles pour optimiser le débit, ou réduisez-la lorsque la pression sur la mémoire est un problème avec les images volumineuses.
Lecture supplémentaire
- Exemple d'analyse ML : comparaison du mode d'analyse avec des exemples de code.
- Comment lire les codes QR : structure de l'entrée et modèles de lecture de base.
- Tutoriel sur le générateur de codes QR : génération avec mise en forme.
- Référence de l'API QrReader : signatures des méthodes et remarques.
- Référence de l'API QrWriter : toutes les surcharges d'écriture.
- Gestion des erreurs : mode d'emploi : isolation des erreurs par fichier et modèles de journalisation.
Voir les options de licence lorsque le pipeline est prêt pour la production.
Questions Fréquemment Posées
Qu'est-ce que le traitement asynchrone de codes QR en C# ?
Le traitement asynchrone de codes QR en C# vous permet d'effectuer des opérations de codes QR sans bloquer le thread principal, en utilisant des fonctionnalités comme la méthode ReadAsync d'IronQR pour améliorer la performance et la réactivité.
Comment le multithreading peut-il améliorer le traitement des codes QR ?
Le multithreading peut considérablement améliorer le traitement des codes QR en permettant à plusieurs opérations de s'exécuter simultanément, facilitant des temps de traitement plus rapides et une efficacité améliorée de l'application grâce à l'utilisation d'IronQR.
Qu'est-ce que la méthode ReadAsync dans IronQR ?
La méthode ReadAsync dans IronQR permet la lecture asynchrone des codes QR, permettant à votre application C# de gérer les données de codes QR sans retarder d'autres tâches.
Comment Parallel.ForEach aide-t-il au traitement des codes QR ?
Parallel.ForEach permet de traiter simultanément plusieurs codes QR en distribuant les tâches sur plusieurs threads, ce qui peut être efficacement utilisé avec IronQR pour accélérer les opérations de code QR.
Quel rôle joue SemaphoreSlim dans les opérations sur les codes QR ?
SemaphoreSlim est utilisé pour limiter le nombre de tâches concurrentes, aidant à gérer les ressources efficacement pendant le traitement parallèle des codes QR avec IronQR.
IronQR peut-il être utilisé pour le traitement des codes QR dans un pipeline limité ?
Oui, IronQR peut être utilisé pour traiter les codes QR dans un pipeline limité, en utilisant des constructions comme SemaphoreSlim pour contrôler la concurrence et l'allocation des ressources.
Quels sont les avantages d'utiliser IronQR pour les opérations asynchrones sur les codes QR ?
Utiliser IronQR pour les opérations asynchrones sur les codes QR améliore la réactivité de l'application, réduit le blocage du thread principal et permet une gestion efficace de gros volumes de données de codes QR.
Est-il possible d'exécuter des opérations sur les codes QR en parallèle en utilisant IronQR ?
Oui, IronQR prend en charge le traitement parallèle des opérations sur les codes QR, vous permettant de tirer parti des capacités de multithreading en C# pour un traitement des codes QR plus rapide et plus efficace.
Comment IronQR améliore-t-il le traitement des codes QR dans les applications C# ?
IronQR améliore le traitement des codes QR en fournissant des capacités robustes d'asynchronie et de multithreading, réduisant les temps de traitement et améliorant la scalabilité des applications C#.
Quelles fonctionnalités C# complètent l'utilisation d'IronQR pour le traitement des codes QR ?
Les fonctionnalités C# telles que async/await, Parallel.ForEach et SemaphoreSlim complètent IronQR, fournissant un cadre pour un traitement des codes QR efficace et haute performance.

