IronQR ハウツー 非同期 & マルチスレッド qrコード 読み取りで非同期とマルチスレッドをC#で使用する方法 カーティス・チャウ 更新日:2026年3月5日 IronQR をダウンロード NuGet ダウンロード 無料トライアル LLM向けのコピー LLM向けのコピー LLM 用の Markdown としてページをコピーする ChatGPTで開く このページについてChatGPTに質問する ジェミニで開く このページについてGeminiに問い合わせる Grokで開く このページについてGrokに質問する 困惑の中で開く このページについてPerplexityに問い合わせる 共有する Facebook で共有 Xでシェア(Twitter) LinkedIn で共有 URLをコピー 記事をメールで送る This article was translated from English: Does it need improvement? Translated View the article in English 単一スレッドのQRスキャンは、すべての画像デコードの間、呼び出しスレッドをブロックします。 WPFのボタンハンドラーでは、デコードが完了するまでUIがフリーズします。 数百枚の画像を処理するバッチ処理では、並列処理が可能なCPUコアがアイドル状態になってしまう。 IronQR の ReadAsync メソッドは個々の読み取りを待機可能なタスクにオフロードし、標準の Read メソッドはバッチ処理のスループットのために Parallel.ForEach および 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 を使い始めましょう無料トライアル Free 30 Day Trial 最小限のワークフロー(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) $vbLabelText $csharpLabel 出力 端末は、デコードされたQRコードの種類と値をoutput-qr.pngが保存されたことを確認します。 QrScanMode.Auto は、機械学習検出と基本的なスキャンパスの両方を実行し、各結果にデコードされた値と 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") $vbLabelText $csharpLabel 出力 コンソールには、処理されたファイル数、処理時間、検出された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 $vbLabelText $csharpLabel 出力 パイプラインが完了すると、コンソールに概要が表示されます。表示されるのは、デコードされたQRコードの総数、ソースファイルの数、経過時間、そして各ファイル名とそのデコードされたURLです。 テストパイプラインのQRコード入力画像20枚すべてをダウンロードしてください(high-volume-qr-images.zip)。 スループットを最大化するために、セマフォの制限値を利用可能なコア数に合わせるか、大きな画像でメモリ負荷が懸念される場合は、制限値を下げてください。 さらなる読み物 MLスキャン例:コードサンプルを用いたスキャンモードの比較。 QRコードの読み取り方法:入力構造と基本的な読み取りパターン。 QRコード生成チュートリアル:スタイル設定付き生成。 QrReader APIリファレンス:メソッドのシグネチャと注釈。 QrWriter API リファレンス:すべての書き込みオーバーロード。 -エラー処理方法:ファイルごとのエラー分離とログ記録パターン。 パイプラインが生産準備が整ったときのライセンスオプションを表示 カーティス・チャウ 今すぐエンジニアリングチームとチャット テクニカルライター Curtis Chauは、カールトン大学でコンピュータサイエンスの学士号を取得し、Node.js、TypeScript、JavaScript、およびReactに精通したフロントエンド開発を専門としています。直感的で美しいユーザーインターフェースを作成することに情熱を持ち、Curtisは現代のフレームワークを用いた開発や、構造の良い視覚的に魅力的なマニュアルの作成を楽しんでいます。開発以外にも、CurtisはIoT(Internet of Things)への強い関心を持ち、ハードウェアとソフトウェアの統合方法を模索しています。余暇には、ゲームをしたりDiscordボットを作成したりして、技術に対する愛情と創造性を組み合わせています。 準備はできましたか? Nuget ダウンロード 63,625 | バージョン: 2026.4 リリース 無料トライアル NuGet 無料ダウンロード 総ダウンロード数: 63,625 ライセンスを見る まだスクロールしていますか? すぐに証拠が欲しいですか? PM > Install-Package IronQR サンプルを実行する URL が QR コードになるのを見る。 NuGet 無料ダウンロード 総ダウンロード数: 63,625 ライセンスを見る