QRコード操作で非同期とマルチスレッドをC#で使用する方法
単一スレッドのQRスキャンは、すべての画像デコードの間、呼び出しスレッドをブロックします。
WPFのボタンハンドラーでは、デコードが完了するまでUIがフリーズします。 数百枚の画像を処理するバッチ処理では、並列処理が可能なCPUコアがアイドル状態になってしまう。 IronQRのTask.WhenAllと連携して動作します。
このガイドでは、QRコードを非同期で処理する方法、バッチ読み取りをCPUコア全体に分散させる方法、および両方のパターンを組み合わせて大容量パイプラインを構築する方法について説明します。
クイックスタート: QRコードを非同期で処理する
画像を読み込み、呼び出し元のスレッドをブロックせずにデコード結果を待機します。
-
IronQR をNuGetパッケージマネージャでインストール
PM > Install-Package IronQR -
このコード スニペットをコピーして実行します。
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); -
実際の環境でテストするためにデプロイする
今日プロジェクトで IronQR を使い始めましょう無料トライアル
最小限のワークフロー(5ステップ)
- 非同期QRコード処理のためのIronQR C#ライブラリをダウンロード
- 非ブロッキングの単一読み取りには
ReadAsync使用してください。 Parallel.ForEachを使用してCPUバウンドバッチ処理を行うSemaphoreSlimと組み合わせて制限付き同時実行パイプラインを作成するIEnumerableから結果を取得し、デコードされた値を表示します。
QRコードを非同期で読み取る
ReadAsync は、待機可能なタスクを返すため、WPF/MAUI のイベントハンドラー、ASP.NET コントローラーのアクション、または任意の非同期メソッドと互換性があります。 入力は画像ビットマップから構築する必要があり、ファイルパスによる指定はできません。
書き込み側は同期処理であり、非同期処理のバリエーションはありません。 ファイル I/O 中にスレッドがブロックされるのを防ぐため、ビットマップからエクスポートされた生バイトデータを使用して、保存ステップを File.WriteAllBytesAsync() でラップしてください。
入力
非同期読み書きパターンを実証するために、QRコードイベントバッジをスキャンして再生成した。
: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)
出力
ターミナルには、デコードされたQRコードのタイプと値が [QrType] Value の形式で表示され、その後 output-qr.png が保存されたことが確認されます。
QrScanMode.Auto は、ML検出と基本スキャン処理の両方を実行し、各結果にデコードされた値とQRコードの種類を格納します。 OnlyDetectionModel は処理が高速ですが、バウンディングボックスの座標のみを返し、値フィールドは空のままになります。 エンコードされたコンテンツが必要な場合は、常に Auto を使用してください。
マルチスレッドによるQRコードの処理
独立してデコード可能な画像については、Parallel.ForEach が利用可能な CPU コア間で処理を分散させます。 IronQRは共有されたリーダーインスタンスに対して明示的なスレッドセーフ性を保証していないため、反復処理ごとに個別の QrReader インスタンスを使用することが安全なデフォルト設定となります。
入力
並列バッチスキャンで使用された10個のQRコードテスト画像のうち4個。 各画像にはURLがエンコードされており、実行時にqr-images/フォルダから読み込まれます。
画像1(全10枚中1枚目)
画像2(全10枚中2枚目)
画像3(全10枚中3枚目)
画像4(全10枚中4枚目)
: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")
出力
コンソールには、処理されたファイル数、処理時間、検出されたQRコード数、発生したエラー、スループットなどを含むバッチの概要が表示されます。 次に、各ファイル名とそのデコードされたURLを一覧表示します。
テストバッチ用のQRコード入力画像10枚すべてをダウンロードしてください(batch-qr-images.zip)。
ConcurrentBag<t> は、ロックを必要とせずにすべてのスレッドから結果を集約します。 スレッドセーフなカウンターが障害を追跡し、各ファイルにtry-catchブロックを使用することで、1つの不良画像がバッチ処理全体を中断させないようにしています。 このアプローチは、エラー処理のハウツーで説明されているエラー分離パターンに従います。
CPUコア数に合わせて、MaxDegreeOfParallelism を Environment.ProcessorCount に変更してください。 スレッド数を増やすとオーバーヘッドが増加するだけで、特にCPU負荷の高い機械学習モデルではパフォーマンスが向上しません。
非同期処理と並列処理の組み合わせ
処理量が多いパイプラインでは、SemaphoreSlim と Task.WhenAll を組み合わせて、並行処理を制限してください。 Parallel.ForEachとは異なり、このパターンではI/Oをノンブロッキングに保ちつつ、一度に実行されるデコードの数を制御することで、大規模なワークロード下でのスレッドプールの飽和を防ぎます。
入力
並列パイプラインによって処理された20枚のQRコードテスト画像のうち4枚。各画像にはURLがエンコードされており、SemaphoreSlimによるバウンド並列処理を用いて並行してデコードされます。
画像1(パイプライン1/20)
画像2(パイプライン2/20)
画像3(パイプライン3/20)
画像4(パイプライン4/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
出力
パイプラインが完了すると、コンソールに概要が表示されます。表示されるのは、デコードされたQRコードの総数、ソースファイルの数、経過時間、そして各ファイル名とそのデコードされたURLです。
テストパイプラインのQRコード入力画像20枚すべてをダウンロードしてください(high-volume-qr-images.zip)。
スループットを最大化するために、セマフォの制限値を利用可能なコア数に合わせるか、大きな画像でメモリ負荷が懸念される場合は、制限値を下げてください。
さらなる読み物
- MLスキャン例:コードサンプルを用いたスキャンモードの比較。
- QRコードの読み取り方法:入力構造と基本的な読み取りパターン。
- QRコード生成チュートリアル:スタイル設定付き生成。
- QrReader APIリファレンス:メソッドのシグネチャと注釈。
- QrWriter API リファレンス:すべての書き込みオーバーロード。 -エラー処理方法:ファイルごとのエラー分離とログ記録パターン。
よくある質問
C# での非同期 QR コード処理とは?
C# での非同期 QR コード処理により、メインスレッドをブロックせずに QR コード操作を行うことができます。IronQR の ReadAsync メソッドのような機能を使用して、パフォーマンスと応答性を向上させます。
マルチスレッド処理は QR コード処理をどのように改善できますか?
マルチスレッド処理は、複数の操作を並行して実行できるようにすることで、QR コード処理を大幅に向上させ、IronQR を使用してアプリケーションの効率を改善します。
IronQR における ReadAsync メソッドとは何ですか?
IronQR の ReadAsync メソッドは、QR コードデータを他のタスクを遅らせることなく処理できるようにする、非同期 QR コード読み取りを可能にします。
Parallel.ForEach は QR コード処理にどのように役立ちますか?
Parallel.ForEach は、複数の QR コードを同時に処理し、タスクを複数のスレッドに分配することで、IronQR との効率的な利用が可能となり、QR コード操作のスピードアップを図れます。
QR コード操作での SemaphoreSlim の役割は何ですか?
SemaphoreSlim は同時実行タスクの数を制限し、IronQR を使った QR コードの並列処理中にリソースを効果的に管理するのを助けます。
IronQR は制限付きパイプラインで QR コードを処理するために使用できますか?
はい、IronQR を使用して、Semaphoreslim のような構造を用いて並行性とリソースの割り当ても制御しながら、制限付きパイプラインで QR コードを処理できます。
非同期 QR コード操作のための IronQR の利点は何ですか?
非同期 QR コード操作のために IronQR を使用することで、アプリケーションの応答性が向上し、メインスレッドでのブロックが減少し、大量のQR コードデータを効率的に処理できます。
IronQR を使用して QR コード操作を並列実行することは可能ですか?
はい、IronQR は QR コード操作の並列処理をサポートしており、C# のマルチスレッド機能を活用して、より迅速かつ効率的な QR コード処理が可能です。
IronQR は C# アプリケーションでの QR コード処理をどのように向上させますか?
IronQR は、強力な非同期およびマルチスレッド機能を提供し、処理時間を短縮し、C# アプリケーションのスケーラビリティを向上させます。
C# のどの機能が QR コード処理のための IronQR の使用を補完しますか?
C# の機能である async/await、Parallel.ForEach、および SemaphoreSlim は IronQR を補完し、効率的で高性能な QR コード処理のためのフレームワークを提供します。

