# Toplu OCR Sırasında Yüksek Tepe Belleği
Birçok PDF segmenti üzerinde OCR çalıştırmak, bellek kullanımını katlar. Her görev, `OcrInput` aracılığıyla tam sayfa bit eşlemlerini işler ve her segment için yeni bir `IronTesseract` motoru, dil modeli dosyalarını her seferinde yeniden yükler. Tam işlemci eşzamanlılığı ile bu, bellek sınırlı ortamlarda arızalanan pik bellek kullanımı ile çoklu GB aralığına itmektedir.
OCR, doğası gereği bellek ağırlıklıdır. Her `OcrInput` tam sayfa bit eşlemlerini işler ve her `IronTesseract` motoru dil modeli dosyalarını belleğe yükler. Her segment için yeni bir motor oluşturarak bu modelleri tekrar tekrar yeniden yüklemiş oluruz ve işlemci çekirdeği başına bir OCR görevini (`Environment.ProcessorCount`) çalıştırmak birçok bit eşlem ağırlıklı işin yan yana çalışmasına olanak tanır. Aktif görev sayısını sınırlayan bir şey olmadığında, pik bellek kullanımı doğrudan eşzamanlılıkla ölçeklenir.
Çözüm, uçuş halindeki iş sayısını sınırlamaktır: eşzamanlılığı sınırlayın, bir havuzdan motorları yeniden kullanın ve çalışmayı bir semaforla yönetin.
## Çözüm
### 1. OCR eşzamanlılığını sınırla
Eşzamanlı OCR görevlerinin sayısını küçük bir tavana sabitleyin. Daha az eşzamanlı görev, bellekte aynı anda daha az tam sayfa resim demektir, bu doğrudan zirve düşer. Tavanı makinenin kapasitesine göre ayarlayın.
```csharp
// Clamp concurrency to avoid memory saturation and CPU over-subscription.
int concurrency = Math.Clamp(Environment.ProcessorCount / 2, 1, 4);
```
### 2. Motorları havuz oluştur
Başlangıçta her eşzamanlı yuva için tam olarak bir `IronTesseract` motoru oluşturun ve dil modelini her seferinde yeni bir motor oluşturmaktan ve yeniden yüklemektense her segmentte bunları yeniden kullanın.
```csharp
// Pre-create one engine per concurrent slot and reuse them across segments.
var enginePool = new ConcurrentBag<IronTesseract>(
Enumerable.Range(0, concurrency).Select(_ => new IronTesseract())
);
```
Havuzu bir kez oluşturmak, dil-model yükleme maliyetini tüm çalışmaya yayar, segment başına ödeme yapmak yerine.
### 3. Çalışmayı bir semaforla sınırla
Eşzamanlılık sınırına bir `SemaphoreSlim` başlatın ve onu `using` içinde sarın. Her görev başlamadan önce `WaitAsync()` çağrısı yapar ve `Release()` bir `finally` içinde yürütülür, böylece yalnızca izin verilen segment sayısı aynı anda işlenir.
```csharp
using var semaphore = new SemaphoreSlim(concurrency);
await semaphore.WaitAsync();
try
{
// Rent a pre-loaded engine from the pool.
if (!enginePool.TryTake(out var ocr))
ocr = new IronTesseract(); // Defensive fallback; should never be reached.
try
{
using var input = new OcrInput();
input.LoadPdf(segmentStream); // page-range segment produced upstream
var ocrResult = await ocr.ReadAsync(input);
ocrResult.SaveAsSearchablePdf(outputPath);
}
finally
{
enginePool.Add(ocr); // Return engine to pool for the next waiting segment.
}
}
finally
{
semaphore.Release();
}
```
`WaitAsync()` çağrısı bir yuva açılana kadar bloke eder ve motora iç `finally` içinde dönerken bir önceden yüklenmiş motoru doğrudan bekleyen bir sonraki segmente teslim eder.
### 4. Her segment için OcrInput'u elden çıkarın
Her `OcrInput`, çalıştırılan sayfa bit eşlemlerinin okuyucu segmentten önce, sonraki görev yuva talebinde bulunmadan serbest bırakılmasını sağlamak için `using` ile sarılır.
[[t:(`using` üzerindeki `OcrInput`, bit eşlem belleğini segmentler arasında birikmesini önleyen şeydir. olmadan, serbest bırakılan yuvalar hala sayfa bit eşlemelerini tutar.)]]
Birçok PDF segmenti üzerinde OCR çalıştırmak, bellek kullanımını katlar. Her görev, OcrInput aracılığıyla tam sayfa bit eşlemlerini işler ve her segment için yeni bir IronTesseract motoru, dil modeli dosyalarını her seferinde yeniden yükler. Tam işlemci eşzamanlılığı ile bu, bellek sınırlı ortamlarda arızalanan pik bellek kullanımı ile çoklu GB aralığına itmektedir.
OCR, doğası gereği bellek ağırlıklıdır. Her OcrInput tam sayfa bit eşlemlerini işler ve her IronTesseract motoru dil modeli dosyalarını belleğe yükler. Her segment için yeni bir motor oluşturarak bu modelleri tekrar tekrar yeniden yüklemiş oluruz ve işlemci çekirdeği başına bir OCR görevini (Environment.ProcessorCount) çalıştırmak birçok bit eşlem ağırlıklı işin yan yana çalışmasına olanak tanır. Aktif görev sayısını sınırlayan bir şey olmadığında, pik bellek kullanımı doğrudan eşzamanlılıkla ölçeklenir.
Çözüm, uçuş halindeki iş sayısını sınırlamaktır: eşzamanlılığı sınırlayın, bir havuzdan motorları yeniden kullanın ve çalışmayı bir semaforla yönetin.
Çözüm
1. OCR eşzamanlılığını sınırla
Eşzamanlı OCR görevlerinin sayısını küçük bir tavana sabitleyin. Daha az eşzamanlı görev, bellekte aynı anda daha az tam sayfa resim demektir, bu doğrudan zirve düşer. Tavanı makinenin kapasitesine göre ayarlayın.
// Clamp concurrency to avoid memory saturation and CPU over-subscription.int concurrency = Math.Clamp(Environment.ProcessorCount / 2, 1, 4);
// Clamp concurrency to avoid memory saturation and CPU over-subscription.
int concurrency = Math.Clamp(Environment.ProcessorCount / 2, 1, 4);
C#
2. Motorları havuz oluştur
Başlangıçta her eşzamanlı yuva için tam olarak bir IronTesseract motoru oluşturun ve dil modelini her seferinde yeni bir motor oluşturmaktan ve yeniden yüklemektense her segmentte bunları yeniden kullanın.
// Pre-create one engine per concurrent slot and reuse them across segments.var enginePool = new ConcurrentBag<IronTesseract>(Enumerable.Range(0, concurrency).Select(_ => new IronTesseract()));
// Pre-create one engine per concurrent slot and reuse them across segments.
var enginePool = new ConcurrentBag<IronTesseract>(
Enumerable.Range(0, concurrency).Select(_ => new IronTesseract())
);
C#
Havuzu bir kez oluşturmak, dil-model yükleme maliyetini tüm çalışmaya yayar, segment başına ödeme yapmak yerine.
3. Çalışmayı bir semaforla sınırla
Eşzamanlılık sınırına bir SemaphoreSlim başlatın ve onu using içinde sarın. Her görev başlamadan önce WaitAsync() çağrısı yapar ve Release() bir finally içinde yürütülür, böylece yalnızca izin verilen segment sayısı aynı anda işlenir.
using var semaphore = new SemaphoreSlim(concurrency);await semaphore.WaitAsync();try{ // Rent a pre-loaded engine from the pool. if (!enginePool.TryTake(out var ocr)) ocr = new IronTesseract(); // Defensive fallback; should never be reached. try { using var input = new OcrInput(); input.LoadPdf(segmentStream); // page-range segment produced upstream var ocrResult = await ocr.ReadAsync(input); ocrResult.SaveAsSearchablePdf(outputPath); } finally { enginePool.Add(ocr); // Return engine to pool for the next waiting segment. }}finally{ semaphore.Release();}
using var semaphore = new SemaphoreSlim(concurrency);
await semaphore.WaitAsync();
try
{
// Rent a pre-loaded engine from the pool.
if (!enginePool.TryTake(out var ocr))
ocr = new IronTesseract(); // Defensive fallback; should never be reached.
try
{
using var input = new OcrInput();
input.LoadPdf(segmentStream); // page-range segment produced upstream
var ocrResult = await ocr.ReadAsync(input);
ocrResult.SaveAsSearchablePdf(outputPath);
}
finally
{
enginePool.Add(ocr); // Return engine to pool for the next waiting segment.
}
}
finally
{
semaphore.Release();
}
C#
WaitAsync() çağrısı bir yuva açılana kadar bloke eder ve motora iç finally içinde dönerken bir önceden yüklenmiş motoru doğrudan bekleyen bir sonraki segmente teslim eder.
4. Her segment için OcrInput'u elden çıkarın
Her OcrInput, çalıştırılan sayfa bit eşlemlerinin okuyucu segmentten önce, sonraki görev yuva talebinde bulunmadan serbest bırakılmasını sağlamak için using ile sarılır.
İpuçları: using üzerindeki OcrInput, bit eşlem belleğini segmentler arasında birikmesini önleyen şeydir. olmadan, serbest bırakılan yuvalar hala sayfa bit eşlemelerini tutar.
Curtis Chau, Bilgisayar Bilimleri alanında Lisans Derecesine (Carleton Üniversitesi) sahip ve Node.js, TypeScript, JavaScript ve React konularında uzmanlaşmış ön uç geliştirmeyle ilgileniyor. Sezgisel ve estetik açıdan hoş kullanıcı arayüzleri oluşturma tutkunu, Curtis modern çerçevelerle çalışmayı ve iyi yapılandırılmış, görsel olarak çekici kılavuzlar oluşturmayı seviyor.