C#에서 QR 코드 작업에 대해 Async 및 멀티 스레드를 사용하는 방법

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

단일 스레드 QR 스캔은 매 이미지 디코드에 대해 호출 스레드를 차단합니다. UI를 동결시키는 WPF 버튼 핸들러에서, 또는 8개의 CPU 코어가 유휴 상태일 때 500개의 이미지를 순차적으로 처리하는 배치 작업에서 고치는 방법은 동일합니다: 디코딩을 호출 스레드에서 이전합니다. IronQR는 비차단 단일 읽기를 위한 ReadAsync과 배치 처리를 위해 Parallel.ForEachTask.WhenAll와 자연스럽게 결합되는 표준 Read 메서드를 제공합니다.

전체 읽기, 병렬 배치 처리, 그리고 통제가 가능한 병행 처리 패턴을 아래에서 다룹니다.

빠른 시작: QR 코드 비동기 처리

이미지를 로드하고 ReadAsync에 전달하여 호출 스레드를 차단하지 않고 디코딩된 결과를 대기합니다.

  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 코드를 비동기적으로 읽는 방법?

QrReader.ReadAsync(IQrInput)Task<IEnumerable<QrResult>>를 반환하며, 비동기 컨텍스트 - WPF/MAUI 이벤트 핸들러, ASP.NET 컨트롤러 액션, 또는 임의의 async Task 메서드에서 직접 대기 가능합니다. 입력은 AnyBitmap에서 QrImageInput로 구성되어야 합니다; 파일 경로 오버로드는 없습니다.

쓰기 측은 다릅니다: QrWriter.Write()는 동기식이며, QrCode.Save()AnyBitmap를 동기적으로 반환합니다 - IronQR은 SaveAsync 메서드를 노출하지 않습니다. 생성 및 저장 워크플로의 파일 I/O 부분에서 차단을 피하기 위해 저장 단계를 File.WriteAllBytesAsync()로 감쌉니다.

: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);
$vbLabelText   $csharpLabel

QrScanMode.OnlyDetectionModel 매개 변수는 리더에게 ML 탐지 모델만을 사용하도록 지시하며, 이는 QrScanMode.Auto (ML + 기본 스캔)보다 이미지 당 빠릅니다. UI 컨텍스트에서 단일 이미지 읽기의 경우 속도 차이는 작습니다; 배치에서는 의미 있게 누적됩니다.

저장 단계에 대한 명시적 주석에 유의하십시오: File.WriteAllBytesAsync()는 .NET Standard이며, IronQR 메서드가 아닙니다. IronQR의 동기 Save()를 I/O 부분의 await와 혼합하는 것이 일반적인 혼란의 원인이기 때문에 이를 지적합니다. ExportBytes() 메서드는 AnyBitmap에 대해 비동기 쓰기를 위한 원시 PNG 바이트 배열을 제공합니다.


QR 코드를 멀티스레딩으로 처리하는 방법?

배치 스캔은 각 이미지를 독립적으로 처리할 수 있을 때 Parallel.ForEach의 이점을 얻습니다. IronQR의 문서가 공유 리더 인스턴스에 대한 명시적 스레드 안전 보장을 하지 않기 때문에, 보수적인 선택으로 스레드마다 QrReader 인스턴스를 새로 생성합니다 - 이는 스레드 안전 기본값입니다.

: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");
$vbLabelText   $csharpLabel

ConcurrentBag<t>는 잠금 없이 스레드 전반에 걸쳐 결과를 수집합니다. Interlocked.Increment는 실패를 안전하게 계산합니다. 파일별로 시도-캐치를 적용하여 하나의 손상된 이미지가 전체 배치를 중단하지 않도록 보장합니다 — 에러 처리 방법에서 설명된 동일한 에러 격리 패턴입니다.

MaxDegreeOfParallelismEnvironment.ProcessorCount로 설정하면 사용 가능한 코어에 스레드 생성이 제한됩니다. 이 이상으로 초과 가입하면 전환 오버헤드는 늘어나지만 처리량은 개선되지 않습니다. 특히 CPU에 종속적인 ML 모델에서는 그렇습니다.

QrImageInput에 전달된 QrScanMode는 이미지 당 비용을 제어하며 배치 전반에 걸쳐 결합됩니다. OnlyDetectionModel는 ML 모델만 실행하며, 이는 인쇄된 깨끗한 코드에 대해 가장 빠릅니다. Auto는 ML 탐지와 기본 스캔 패스를 모두 실행하여 손상되거나 기울어진 코드에 대한 속도를 정확도로 바꿔줍니다. OnlyBasicScan는 ML을 완전히 우회하여 전통적인 디코더만 사용합니다. 이미지 품질이 일관적인 기계 인쇄 라벨의 배치 처리의 경우 OnlyDetectionModel는 최고의 처리량을 제공합니다. QR 코드가 부분적으로 가려진 문서 스캔의 경우, Auto는 대략 이미지 당 2배의 시간이 소요되더라도 더 안전한 선택입니다.


비동기 및 병렬 처리를 결합하는 방법?

대량 파이프라인의 프로덕션 패턴은 ReadAsyncTask.WhenAll 팬아웃 내부에서 실행하는 동안 동시에 SemaphoreSlim를 사용하여 동시성을 제한합니다. 이는 비막힘 I/O(이미지 로딩)과 제어된 CPU 병렬 처리(ML 디코딩)를 조합하여 스레드 풀이 포화되지 않도록 합니다.

: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");
$vbLabelText   $csharpLabel

규모에서 QrScanMode 선택이 중요합니다. ReadAsync는 카메라 프레임과 배치 처리에 이상적인 최적 속도를 위해 최적화된 ML 탐지 모델만 실행합니다. Auto은 손상된 코드에 대해 약 2배의 이미지 단가로 더 높은 정확도를 위해 ML과 기본 스캔 패스를 결합합니다. OnlyBasicScan는 ML을 완전히 건너뛰고 전통적인 디코더만 사용합니다. 청결하게 인쇄된 QR 라벨을 처리하는 프로덕션 파이프라인의 경우, OnlyDetectionModel가 처리량-정확도 간의 최상의 균형을 제공합니다.


내 다음 단계는 무엇인가요?

мы расмотрели ReadAsync для блочно-блокирующих QR чтений, Parallel.ForEach для загрузки пакетных потоков и SemaphoreSlim + Task.WhenAll для ограниченной асинхронной параллелизм. QrScanMode 열거형은 이미지 당 수준에서 속도-정확도의 균형을 컨트롤하며, 대량 파이프라인에 대한 적당한 기본값은 OnlyDetectionModel입니다.

추가 읽기 자료:

라이선스 옵션 보기 when the pipeline is ready for production.

A PHP Error was encountered

Severity: Warning

Message: Illegal string offset 'name'

Filename: sections/author_component.php

Line Number: 18

Backtrace:

File: /var/www/ironpdf.com/application/views/main/sections/author_component.php
Line: 18
Function: _error_handler

File: /var/www/ironpdf.com/application/libraries/Render.php
Line: 63
Function: view

File: /var/www/ironpdf.com/application/views/products/sections/three_column_docs_page_structure.php
Line: 64
Function: main_view

File: /var/www/ironpdf.com/application/libraries/Render.php
Line: 88
Function: view

File: /var/www/ironpdf.com/application/views/products/how-to/index.php
Line: 2
Function: view

File: /var/www/ironpdf.com/application/libraries/Render.php
Line: 88
Function: view

File: /var/www/ironpdf.com/application/libraries/Render.php
Line: 552
Function: view

File: /var/www/ironpdf.com/application/controllers/Products/Howto.php
Line: 31
Function: render_products_view

File: /var/www/ironpdf.com/index.php
Line: 292
Function: require_once

A PHP Error was encountered

Severity: Warning

Message: Illegal string offset 'title'

Filename: sections/author_component.php

Line Number: 38

Backtrace:

File: /var/www/ironpdf.com/application/views/main/sections/author_component.php
Line: 38
Function: _error_handler

File: /var/www/ironpdf.com/application/libraries/Render.php
Line: 63
Function: view

File: /var/www/ironpdf.com/application/views/products/sections/three_column_docs_page_structure.php
Line: 64
Function: main_view

File: /var/www/ironpdf.com/application/libraries/Render.php
Line: 88
Function: view

File: /var/www/ironpdf.com/application/views/products/how-to/index.php
Line: 2
Function: view

File: /var/www/ironpdf.com/application/libraries/Render.php
Line: 88
Function: view

File: /var/www/ironpdf.com/application/libraries/Render.php
Line: 552
Function: view

File: /var/www/ironpdf.com/application/controllers/Products/Howto.php
Line: 31
Function: render_products_view

File: /var/www/ironpdf.com/index.php
Line: 292
Function: require_once

A PHP Error was encountered

Severity: Warning

Message: Illegal string offset 'comment'

Filename: sections/author_component.php

Line Number: 48

Backtrace:

File: /var/www/ironpdf.com/application/views/main/sections/author_component.php
Line: 48
Function: _error_handler

File: /var/www/ironpdf.com/application/libraries/Render.php
Line: 63
Function: view

File: /var/www/ironpdf.com/application/views/products/sections/three_column_docs_page_structure.php
Line: 64
Function: main_view

File: /var/www/ironpdf.com/application/libraries/Render.php
Line: 88
Function: view

File: /var/www/ironpdf.com/application/views/products/how-to/index.php
Line: 2
Function: view

File: /var/www/ironpdf.com/application/libraries/Render.php
Line: 88
Function: view

File: /var/www/ironpdf.com/application/libraries/Render.php
Line: 552
Function: view

File: /var/www/ironpdf.com/application/controllers/Products/Howto.php
Line: 31
Function: render_products_view

File: /var/www/ironpdf.com/index.php
Line: 292
Function: require_once

시작할 준비 되셨나요?
Nuget 다운로드 61,359 | 버전: 2026.3 방금 출시되었습니다
Still Scrolling Icon

아직도 스크롤하고 계신가요?

빠른 증거를 원하시나요? PM > Install-Package IronQR
샘플을 실행하세요 URL이 QR 코드로 바뀌는 것을 확인해 보세요.