如何在C&#35中使用非同步和多執行緒進行QR碼操作

This article was translated from English: Does it need improvement?
Translated
View the article in English

單執行緒QR掃描會在每次圖像解碼期間阻塞呼叫執行緒。

在WPF按鈕處理程式中,這將會凍結UI,直到解碼完成。 在處理數百張圖像的批次工作中,當CPU核心可以並行工作時,則會處於閒置狀態。 IronQR的Task.WhenAll批量吞吐量。

本指南演示了如何非同步處理QR碼,分配批量讀取到CPU核心,並結合這兩種模式以實現高容量流水線。

快速入門:非同步處理QR碼

載入圖片並在不阻塞呼叫執行緒的情況下等待解碼結果。

  1. 使用NuGet套件管理器安裝https://www.nuget.org/packages/IronQR

    PM > Install-Package IronQR
  2. 複製並運行這段程式碼片段。

    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);
  3. 部署以在您的實時環境中測試

    今天就開始在您的專案中使用IronQR,透過免費試用

    arrow pointer

以非同步方式讀取QR碼

ReadAsync返回一個可等待的任務,使其可以與WPF/MAUI事件處理程式、ASP.NET控制器動作或任何非同步方法相容。 輸入必須從圖像位圖構建,沒有文件路徑的重載。

寫入方是同步的,沒有非同步變體。 為避免在文件I/O期間阻塞執行緒,使用從位圖導出的原始字節將保存步驟包裝在File.WriteAllBytesAsync()中。

輸入

掃描並重新生成的QR碼事件徽章,以展示非同步讀寫模式。

QR碼編碼https://ironsoftware.com/event-badge作為非同步讀取輸入
: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)
$vbLabelText   $csharpLabel

輸出

終端顯示解碼的QR型別和值格式output-qr.png已保存。

終端輸出顯示[QRCode]解碼值和output-qr.png保存確認

QrScanMode.Auto同時運行ML檢測和基本掃描,填充每個結果中的解碼值和QR型別。 OnlyDetectionModel速度更快,但僅返回邊框座標,值字段留空。 需要編碼內容時使用Auto


使用多執行緒處理QR碼

對於可以獨立解碼的圖像,Parallel.ForEach分配工作到可用的CPU核心。 每次迭代一個單獨的QrReader實例是安全的預設值,因為IronQR沒有明確的執行緒安全保證。

輸入

平行批次掃描中用於測試的十張QR碼圖像中的四張。 每張圖片編碼一個URL,並在運行時從qr-images/文件夾中讀取。

批次 QR code 輸入影像 10 張中的第 1 張,編碼 https://ironsoftware.com/batch-1
批次 QR code 輸入影像 10 張中的第 2 張,編碼 https://ironsoftware.com/batch-2
批次 QR code 輸入影像 10 張中的第 3 張,編碼 https://ironsoftware.com/batch-3
批次 QR code 輸入影像 10 張中的第 4 張,編碼 https://ironsoftware.com/batch-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")
$vbLabelText   $csharpLabel

輸出

控制台顯示批次摘要,包括處理的文件數、處理時間、找到的QR碼、任何失敗和吞吐量。 然後列出每個文件名及其解碼的URL。

終端輸出顯示平行批次結果:已處理10個文件,找到的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以有限併發進行平行解碼。

管線 QR 碼輸入影像,第 1 張,共 20 張
管線 QR 碼輸入影像,第 2 張,共 20 張
管線 QR 碼輸入影像,第 3 張,共 20 張
管線 QR 碼輸入影像,第 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
$vbLabelText   $csharpLabel

輸出

當流水線完成後,控制台顯示摘要:總計解碼的QR碼數量、源文件數量和經過時間,隨後是每個文件名及其解碼的URL。

終端輸出顯示流水線結果:從20個文件中解碼的20個QR碼,每個文件名解碼的URL

下載所有20個測試流水線QR碼輸入圖像 (high-volume-qr-images.zip)。

將信號閘限制與可用核心數匹配以提高吞吐量,或在大型圖像下記憶體壓力成為問題時降低。


進一步閱讀

檢視授權選項,當流水線準備好進入生產時。

常見問題

什麼是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碼處理框架。

Curtis Chau
技術作家

Curtis Chau擁有Carleton大學的電腦科學學士學位,專精於前端開發,擁有Node.js、TypeScript、JavaScript和React的專業知識。Curtis熱衷於建立直觀且美觀的使用者介面,喜愛使用現代框架並建立結構良好、視覺吸引力的手冊。

除了開發,Curtis對物聯網(IoT)有濃厚的興趣,探索創新的方法來整合硬體和軟體。在空閒時間,他喜歡玩遊戲和建立Discord機器人,結合他對技術的熱愛與創造力。

準備好開始了嗎?
Nuget 下載 70,398 | 版本: 2026.7 剛剛發布
Still Scrolling Icon

還在滾動?

想要快速證明嗎? PM > Install-Package IronQR
執行一個範例 觀看您的URL變成QR碼。