QRコード操作で非同期とマルチスレッドをC#で使用する方法
単一スレッドのQRスキャンは、すべての画像デコードの間、呼び出しスレッドをブロックします。
WPFのボタンハンドラーでは、デコードが完了するまでUIがフリーズします。 数百枚の画像を処理するバッチ処理では、並列処理が可能なCPUコアがアイドル状態になってしまう。 IronQRのTask.WhenAllと連携して動作します。
このガイドでは、QRコードを非同期で処理する方法、バッチ読み取りをCPUコア全体に分散させる方法、および両方のパターンを組み合わせて大容量パイプラインを構築する方法について説明します。
クイックスタート: QRコードを非同期で処理する
画像を読み込み、呼び出し元のスレッドをブロックせずにデコード結果を待機します。
-
IronQR をNuGetパッケージマネージャでインストール
-
このコード スニペットをコピーして実行します。
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<QrResult>から結果を取得し、デコードされた値を表示します。
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.Auto);
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.Auto)
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タイプと値がoutput-qr.pngが保存されたことが確認されます。
QrScanMode.Autoは、ML検出と基本的なスキャンパスを両方実行し、各結果にデコード済みの値とQRタイプを入力します。 OnlyDetectionModelはより速いですが、バウンディングボックスの座標のみを返し、値フィールドは空のままです。 エンコードされたコンテンツが必要なときはいつでもAutoを使用してください。
マルチスレッドによるQRコードの処理
独立してデコードできる画像に対して、Parallel.ForEachは利用可能なCPUコアに作業を分散します。 各イテレーションごとのQrReaderインスタンスが安全なデフォルトです。IronQRは、共有リーダーインスタンスの明確なスレッドセーフティについて保証していないためです。
入力
並列バッチスキャンで使用された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.Auto);
// 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.Auto)
' 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コアの数に合わせるために、Environment.ProcessorCountに設定してください。 スレッド数を増やすとオーバーヘッドが増加するだけで、特にCPU負荷の高い機械学習モデルではパフォーマンスが向上しません。
非同期処理と並列処理の組み合わせ
高ボリュームのパイプラインには、SemaphoreSlimを使用し、同時並行性を制限してください。 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);
// Auto: runs ML detection plus a basic scan so result.Value is populated
var input = new QrImageInput(bmp, QrScanMode.Auto);
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)
' Auto: runs ML detection plus a basic scan so result.Value is populated
Dim input = New QrImageInput(bmp, QrScanMode.Auto)
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 コード処理のためのフレームワークを提供します。

