如何在C#中使用非同步和多執行緒進行QR碼操作
單執行緒QR掃描會在每次圖像解碼期間阻塞呼叫執行緒。
在WPF按鈕處理程式中,這將會凍結UI,直到解碼完成。 在處理數百張圖像的批次工作中,當CPU核心可以並行工作時,則會處於閒置狀態。 IronQR的Task.WhenAll批量吞吐量。
本指南演示了如何非同步處理QR碼,分配批量讀取到CPU核心,並結合這兩種模式以實現高容量流水線。
快速入門:非同步處理QR碼
載入圖片並在不阻塞呼叫執行緒的情況下等待解碼結果。
-
使用NuGet套件管理器安裝https://www.nuget.org/packages/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<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沒有明確的執行緒安全保證。
輸入
平行批次掃描中用於測試的十張QR碼圖像中的四張。 每張圖片編碼一個URL,並在運行時從qr-images/文件夾中讀取。
圖像1 (批次1,共10批)
圖像2 (批次2,共10批)
圖像3 (批次3,共10批)
圖像4 (批次4,共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.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。
下載所有10個測試批次QR碼輸入圖像 (batch-qr-images.zip)。
ConcurrentBag<t>從所有執行緒中收集結果,而不需要鎖定。 一個執行緒安全的計數器追蹤失敗,並使用try-catch保護每個文件,確保一個壞圖像不會中斷整個批次。 此方法遵循錯誤處理指南中描述的錯誤隔離模式。
將Environment.ProcessorCount以對齊CPU核心數。 使用額外的執行緒會增加開銷且不提高性能,尤其是對於CPU密集型ML模型。
結合非同步和平行處理
對於高容量流水線,使用Task.WhenAll配對以限制併發性。 這種模式不同於Parallel.ForEach,保持I/O非阻塞,同時控制同時運行的解碼數,防止在大量工作負荷下執行緒池飽和。
輸入
處理併發流水線中的二十張QR碼測試圖像中的四張。每個圖像都編碼了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。
下載所有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等構建來有效控制併發和資源分配。
使用IronQR進行非同步QR碼操作有什麼好處?
使用IronQR進行非同步QR碼操作可以提高應用程式的響應能力,減少主執行緒的阻塞,並能有效處理大量的QR碼資料。
是否可以使用IronQR並行運行QR碼操作?
是的,IronQR支持QR碼操作的並行處理,允許您在C#中利用多執行緒的能力,進行更快速和更高效的QR碼處理。
IronQR如何增強C#應用程式中的QR碼處理?
IronQR通過提供強大的非同步和多執行緒能力來增強QR碼處理,減少處理時間並提高C#應用程式的擴展性。
哪些C#功能補充使用IronQR進行QR碼處理?
如async/await、Parallel.ForEach和SemaphoreSlim等C#功能,補充了IronQR提供高效和高性能的QR碼處理框架。

