如何在 C# 中使用 Async 和多執行緒進行 QR 碼操作
單執行緒的 QR 碼掃描會在每次影像解碼期間阻塞呼叫執行緒。
在 WPF 按鈕處理程序中,這會導致使用者介面凍結,直到解碼完成為止。 在處理數百張圖片的批次工作任務中,這會導致 CPU 核心閒置,而這些核心本可進行平行運算。 IronQR 的 ReadAsync 方法會將個別讀取作業委派給可等待的任務,而標準的 Read 方法則搭配 Parallel.ForEach 和 Task.WhenAll 來處理批次吞吐量。
本指南將示範如何異步處理 QR 碼、將批次讀取任務分配至各 CPU 核心,以及如何結合這兩種模式以建構高吞吐量的處理管道。
快速入門:異步處理 QR 碼
載入圖片並等待解碼結果,同時不阻塞呼叫執行緒。
-
using NuGet 套件管理員安裝 https://www.nuget.org/packages/IronQR
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 個步驟)
- 下載 IronQR C# 程式庫,以進行非同步 QR 碼處理
- 使用
ReadAsync進行非阻塞單次讀取 - 使用
Parallel.ForEach進行 CPU 密集型批次處理 - 結合
SemaphoreSlim實現有限並發管線 - 從
IEnumerable收集結果並 PRINT 解碼後的值
異步讀取 QR 碼
ReadAsync 會傳回一個可等待的任務 (awaitable task),使其相容於 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)
輸出
終端機以 [QrType] Value 的格式顯示解碼後的 QR 類型與值,隨後確認已儲存 output-qr.png。
QrScanMode.Auto 同時執行機器學習偵測與基礎掃描流程,並在每個結果中填入解碼值與 QR 碼類型。 OnlyDetectionModel 速度較快,但僅返回邊界框座標,且值欄位保持為空。 凡需呈現編碼內容之處,請使用 Auto。
使用多執行緒處理 QR 碼
對於可獨立解碼的影像,Parallel.ForEach 會將工作分配至可用的 CPU 核心上。 每次迭代使用獨立的 QrReader 實例是安全的預設做法,因為 IronQR 並未針對共享的讀取器實例提供明確的執行緒安全性保證。
輸入
在並行批次掃描中使用的十張 QR 碼測試圖像中的四張。 每張圖片均內嵌一個 URL,並於執行時從 qr-images/ 資料夾中讀取。
圖片 1(第 1 批,共 10 張)
圖片 2(共 10 張,第 2 張)
圖片 3(第 3 批,共 10 批)
圖片 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。
下載全部 10 張測試批次 QR 碼輸入圖片 (batch-qr-images.zip)。
ConcurrentBag<t> 可在無需鎖定的情況下,彙整所有執行緒的結果。 一個線程安全的計數器會追蹤失敗次數,而對每個檔案使用 try-catch 語法,可確保單張損壞的圖片不會中斷整個批次處理流程。 此方法遵循《錯誤處理實作指南》中所述的錯誤隔離模式。
將 MaxDegreeOfParallelism 設定為 Environment.ProcessorCount,以配合 CPU 核心數。 使用額外的執行緒會增加系統開銷,且無法提升效能,對於 CPU 密集型的機器學習模型而言尤其如此。
結合非同步與並行處理
對於高負載的處理流程,請將 SemaphoreSlim 與 Task.WhenAll 搭配使用以限制並發處理。 與 Parallel.ForEach 不同,此模式在保持 I/O 非阻塞的同時,能控制同時執行的解碼數量,從而避免在高負載情況下發生執行緒池飽和。
輸入
這是由並行處理管線處理的二十張 QR 碼測試圖像中的四張。每張圖像皆編碼了一個 URL,並透過 SemaphoreSlim 採用有限並行處理進行平行解碼。
圖片 1(共 20 張中的第 1 張)
圖片 2(共 20 張中的第 2 張)
圖片 3(共 20 張中的第 3 張)
圖片 4(共 20 張中的第 4 張)
: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。
下載全部 20 張測試管道 QR 碼輸入圖片 (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 碼的異步讀取,讓您的 C# 應用程式能在不延遲其他任務的情況下處理 QR 碼資料。
Parallel.ForEach 在 QR 碼處理中如何發揮作用?
Parallel.ForEach 透過將任務分配至多個執行緒,實現同時處理多個 QR 碼,並可與 IronQR 有效配合,以加速 QR 碼相關操作。
SemaphoreSlim 在 QR 碼操作中扮演什麼角色?
SemaphoreSlim 用於限制同時執行的任務數量,有助於在使用 IronQR 進行 QR 碼並行處理時,有效管理資源。
IronQR 能否用於在封閉式處理流程中處理 QR 碼?
是的,IronQR 可用於在封閉式處理流程中處理 QR 碼,並透過 SemaphoreSlim 等結構有效控制並發性與資源分配。
using IronQR 進行非同步 QR 碼操作有哪些優勢?
using IronQR 進行非同步 QR 碼操作,可提升應用程式的反應速度、減少主執行緒的阻塞,並能高效處理大量 QR 碼資料。
是否可以使用 IronQR 並行執行 QR 碼相關操作?
是的,IronQR 支援 QR 碼操作的並行處理,讓您能利用 C# 的多執行緒功能,實現更快、更高效的 QR 碼處理。
IronQR 如何提升 C# 應用程式中的 QR 碼處理能力?
IronQR 透過提供強大的非同步與多執行緒功能,強化 QR 碼處理能力,從而縮短處理時間並提升 C# 應用程式的可擴展性。
哪些 C# 功能能與 IronQR 配合使用,以進行 QR 碼處理?
C# 的功能(例如 async/await、Parallel.ForEach 及 SemaphoreSlim)與 IronQR 相輔相成,共同提供了一個高效且高性能的 QR 碼處理框架。

