.NET幫助 C# SemaphoreSlim(對開發者如何理解的工作) Curtis Chau 更新日期:7月 28, 2025 Download IronPDF NuGet 下載 DLL 下載 Windows 安裝程式 Start Free Trial Copy for LLMs Copy for LLMs Copy page as Markdown for LLMs Open in ChatGPT Ask ChatGPT about this page Open in Gemini Ask Gemini about this page Open in Grok Ask Grok about this page Open in Perplexity Ask Perplexity about this page Share Share on Facebook Share on X (Twitter) Share on LinkedIn Copy URL Email article 並發性管理是 C# 中高性能應用程式的一個關鍵方面。 它確保資源得到有效利用,同時避免潛在的衝突或性能瓶頸,因此使用輕量級的信號量來控制訪問可能非常有幫助。 這就是 SemaphoreSlim 的作用所在。 SemaphoreSlim 是一種輕量級的同步原語,用於控制資源訪問,最終防止競爭條件並確保線程安全。 那麼,如果您想將其與 PDF 庫一起使用以管理 PDF 生成過程呢? 您可能正在尋找一個強大的 PDF 庫,此時 IronPDF 派上用場。 IronPDF 是一個強大的 PDF 生成和操作庫,供 .NET 開發人員使用,當在多線程環境中使用時,可以大大受益於並發性管理。 如果您想查看 SemaphoreSlim 和 IronPDF 的實際應用,請繼續閱讀,我們將探討使用 SemaphoreSlim 的好處以及如何將其與 IronPDF 集成以安全地處理並發操作、提高性能並確保可靠的 PDF 處理。 理解 C# 中的 SemaphoreSlim 什麼是 SemaphoreSlim? SemaphoreSlim 是 .NET 中的同步原語,限制可以同時訪問特定資源或資源池的線程數。 它是完整 Semaphore 類的輕量版本,設計用於在更簡單、更快的信號量足夠的情況下更高效地工作。 使用 SemaphoreSlim 的一些好處是系統開銷減少與 Semaphore 相比,適合管理有限資源(如數據庫連接或文件訪問),並且支持異步等待方法,非常適合現代的 async/await 程式設計模式。 基本使用 SemaphoreSlim 的代碼範例 using System; using System.Threading; using System.Threading.Tasks; class Program { // Semaphore count private static SemaphoreSlim _semaphore = new SemaphoreSlim(3); // Limit to 3 concurrent threads. static async Task Main(string[] args) { // Start tasks that will wait on the semaphore. var tasks = new Task[5]; for (int i = 0; i < tasks.Length; i++) { tasks[i] = Task.Run(() => AccessResource(i)); } // Simulate some work in the main thread (e.g., initialization). Console.WriteLine("Main thread is preparing resources..."); await Task.Delay(2000); // Simulate initialization delay. // Main thread calls release, releases semaphore permits to allow waiting tasks to proceed. Console.WriteLine("Main thread releasing semaphore permits..."); _semaphore.Release(2); // Releases 2 permits, allowing up to 2 tasks to proceed. // Wait for all tasks to complete. await Task.WhenAll(tasks); Console.WriteLine("All tasks completed."); } static async Task AccessResource(int id) { Console.WriteLine($"Task {id} waiting to enter..."); await _semaphore.WaitAsync(); try { Console.WriteLine($"Current thread successfully entered by Task {id}."); await Task.Delay(1000); // Simulate work. } finally { Console.WriteLine($"Task {id} releasing."); _semaphore.Release(); } } } using System; using System.Threading; using System.Threading.Tasks; class Program { // Semaphore count private static SemaphoreSlim _semaphore = new SemaphoreSlim(3); // Limit to 3 concurrent threads. static async Task Main(string[] args) { // Start tasks that will wait on the semaphore. var tasks = new Task[5]; for (int i = 0; i < tasks.Length; i++) { tasks[i] = Task.Run(() => AccessResource(i)); } // Simulate some work in the main thread (e.g., initialization). Console.WriteLine("Main thread is preparing resources..."); await Task.Delay(2000); // Simulate initialization delay. // Main thread calls release, releases semaphore permits to allow waiting tasks to proceed. Console.WriteLine("Main thread releasing semaphore permits..."); _semaphore.Release(2); // Releases 2 permits, allowing up to 2 tasks to proceed. // Wait for all tasks to complete. await Task.WhenAll(tasks); Console.WriteLine("All tasks completed."); } static async Task AccessResource(int id) { Console.WriteLine($"Task {id} waiting to enter..."); await _semaphore.WaitAsync(); try { Console.WriteLine($"Current thread successfully entered by Task {id}."); await Task.Delay(1000); // Simulate work. } finally { Console.WriteLine($"Task {id} releasing."); _semaphore.Release(); } } } Imports System Imports System.Threading Imports System.Threading.Tasks Friend Class Program ' Semaphore count Private Shared _semaphore As New SemaphoreSlim(3) ' Limit to 3 concurrent threads. Shared Async Function Main(ByVal args() As String) As Task ' Start tasks that will wait on the semaphore. Dim tasks = New Task(4){} For i As Integer = 0 To tasks.Length - 1 tasks(i) = Task.Run(Function() AccessResource(i)) Next i ' Simulate some work in the main thread (e.g., initialization). Console.WriteLine("Main thread is preparing resources...") Await Task.Delay(2000) ' Simulate initialization delay. ' Main thread calls release, releases semaphore permits to allow waiting tasks to proceed. Console.WriteLine("Main thread releasing semaphore permits...") _semaphore.Release(2) ' Releases 2 permits, allowing up to 2 tasks to proceed. ' Wait for all tasks to complete. Await Task.WhenAll(tasks) Console.WriteLine("All tasks completed.") End Function Private Shared Async Function AccessResource(ByVal id As Integer) As Task Console.WriteLine($"Task {id} waiting to enter...") Await _semaphore.WaitAsync() Try Console.WriteLine($"Current thread successfully entered by Task {id}.") Await Task.Delay(1000) ' Simulate work. Finally Console.WriteLine($"Task {id} releasing.") _semaphore.Release() End Try End Function End Class $vbLabelText $csharpLabel 在程序運行期間,當所有可用許可證都已被線程獲得時,信號量的計數可以動態達到零線程。 此狀態表示已達到允許的最大並發訪問量。 如果您願意,您可以設置初始和最大線程數,將初始信號量計數設置為零,然後使用單獨的初始化任務在資源準備就緒時增加信號量計數,允許您選擇的線程數繼續。 當信號量計數為零時,線程在嘗試進入信號量時將等待,這稱為“阻塞等待”。 您可以跟踪以前的信號量計數以根據以前的計數調整信號量的行為。 然後,您可以相應地操作信號量(例如,通過釋放或等待)。 隨著線程釋放,信號量計數會減少。 控制台輸出 SemaphoreSlim 的常見用法 SemaphoreSlim 的一些常見用法包括: 限制對數據庫或文件系統的訪問:這可以防止這些資源因過多並發請求而負擔過重。 管理線程池:可以用於控制執行特定操作的線程數量,從而提高穩定性和性能。 在 IronPDF 中使用 SemaphoreSlim 進行安全的並發控制 在多線程環境中設置 IronPDF 要開始在多線程環境中使用 IronPDF,首先安裝 IronPDF NuGet 程式包。 您可以通過導航到工具 > NuGet 包管理器 > 解決方案的 NuGet 包管理器並搜索 IronPDF 來完成此操作: 或者,在包管理器控制台運行以下命令: Install-Package IronPdf 要在代碼中開始使用 IronPDF,請確保將 using IronPdf 語句放在代碼文件的頂部。有關在環境中設置 IronPDF 的更深入指南,請查看其入門頁面。 使用 SemaphoreSlim 控制對 PDF 生成的訪問 使用 SemaphoreSlim 時,您可以有效地控制對 PDF 生成任務的訪問。 這可確保您的應用程式不會嘗試同時生成過多的 PDF,這可能影響性能或導致故障。 以下示例代碼展示了 SemaphoreSlim 與 IronPDF 的基本用法。 using IronPdf; using System; using System.Threading; using System.Threading.Tasks; class Program { private static SemaphoreSlim _semaphore = new SemaphoreSlim(2); // Limit to 2 concurrent threads. static async Task Main(string[] args) { var tasks = new Task[5]; for (int i = 0; i < tasks.Length; i++) { string htmlContent = $"<h1>PDF Document {i}</h1><p>This is a sample PDF content for task {i}.</p>"; string outputPath = $"output_{i}.pdf"; // Start multiple tasks to demonstrate controlled concurrency. tasks[i] = GeneratePdfAsync(htmlContent, outputPath, i); } await Task.WhenAll(tasks); } static async Task GeneratePdfAsync(string htmlContent, string outputPath, int taskId) { Console.WriteLine($"Task {taskId} is waiting for access..."); // Wait to enter the semaphore. await _semaphore.WaitAsync(); try { Console.WriteLine($"Task {taskId} has started PDF generation."); ChromePdfRenderer renderer = new ChromePdfRenderer(); PdfDocument pdf = await renderer.RenderHtmlAsPdfAsync(htmlContent); pdf.SaveAs(outputPath); Console.WriteLine($"Task {taskId} has completed PDF generation."); } finally { // Ensure semaphore is released to allow other tasks to proceed. _semaphore.Release(); Console.WriteLine($"Task {taskId} has released semaphore."); } } } using IronPdf; using System; using System.Threading; using System.Threading.Tasks; class Program { private static SemaphoreSlim _semaphore = new SemaphoreSlim(2); // Limit to 2 concurrent threads. static async Task Main(string[] args) { var tasks = new Task[5]; for (int i = 0; i < tasks.Length; i++) { string htmlContent = $"<h1>PDF Document {i}</h1><p>This is a sample PDF content for task {i}.</p>"; string outputPath = $"output_{i}.pdf"; // Start multiple tasks to demonstrate controlled concurrency. tasks[i] = GeneratePdfAsync(htmlContent, outputPath, i); } await Task.WhenAll(tasks); } static async Task GeneratePdfAsync(string htmlContent, string outputPath, int taskId) { Console.WriteLine($"Task {taskId} is waiting for access..."); // Wait to enter the semaphore. await _semaphore.WaitAsync(); try { Console.WriteLine($"Task {taskId} has started PDF generation."); ChromePdfRenderer renderer = new ChromePdfRenderer(); PdfDocument pdf = await renderer.RenderHtmlAsPdfAsync(htmlContent); pdf.SaveAs(outputPath); Console.WriteLine($"Task {taskId} has completed PDF generation."); } finally { // Ensure semaphore is released to allow other tasks to proceed. _semaphore.Release(); Console.WriteLine($"Task {taskId} has released semaphore."); } } } Imports IronPdf Imports System Imports System.Threading Imports System.Threading.Tasks Friend Class Program Private Shared _semaphore As New SemaphoreSlim(2) ' Limit to 2 concurrent threads. Shared Async Function Main(ByVal args() As String) As Task Dim tasks = New Task(4){} For i As Integer = 0 To tasks.Length - 1 Dim htmlContent As String = $"<h1>PDF Document {i}</h1><p>This is a sample PDF content for task {i}.</p>" Dim outputPath As String = $"output_{i}.pdf" ' Start multiple tasks to demonstrate controlled concurrency. tasks(i) = GeneratePdfAsync(htmlContent, outputPath, i) Next i Await Task.WhenAll(tasks) End Function Private Shared Async Function GeneratePdfAsync(ByVal htmlContent As String, ByVal outputPath As String, ByVal taskId As Integer) As Task Console.WriteLine($"Task {taskId} is waiting for access...") ' Wait to enter the semaphore. Await _semaphore.WaitAsync() Try Console.WriteLine($"Task {taskId} has started PDF generation.") Dim renderer As New ChromePdfRenderer() Dim pdf As PdfDocument = Await renderer.RenderHtmlAsPdfAsync(htmlContent) pdf.SaveAs(outputPath) Console.WriteLine($"Task {taskId} has completed PDF generation.") Finally ' Ensure semaphore is released to allow other tasks to proceed. _semaphore.Release() Console.WriteLine($"Task {taskId} has released semaphore.") End Try End Function End Class $vbLabelText $csharpLabel 在這個例子中,我們首先初始化 SemaphoreSlim 並將 SemaphoreSlim 的初始和最大計數設置為“2”,將其限制為兩個並發的 PDF 生成。 然後,我們創建了一個任務數組,用於控制程序必須執行的任務數量,隨後我們使用 for 循環根據任務數組中的任務數量動態創建 PDF。 然後使用 WaitAsync() 方法進入信號量,在 finally 塊中使用 Release() 確保即使發生異常也始終釋放信號量。 控制臺輸出日誌顯示每個任務開始、結束和釋放信號量的時間,這使您可以跟踪並發行為。 控制台輸出 PDF 文件輸出 確保 PDF 操作任務中的線程安全性 當多個線程與共享資源交互時,線程安全性至關重要。 在 PDF 操作中,SemaphoreSlim 確保只有定義數量的線程可以同時修改 PDF,防止競爭條件並確保一致性。 在以下代碼中,我們正在模擬一個場景,其中我們將水印添加到多個 PDF,同時確保每次只執行一個操作。 using IronPdf; using System; using System.Threading; using System.Threading.Tasks; class Program { private static SemaphoreSlim _semaphore = new SemaphoreSlim(1); static async Task Main(string[] args) { // Setting array of tasks var tasks = new Task[3]; for (int i = 0; i < tasks.Length; i++) { string inputPath = $"input_{i}.pdf"; // Input PDF file path string outputPath = $"output_{i}.pdf"; // Output PDF file path string watermarkText = @" <img src='https://ironsoftware.com/img/products/ironpdf-logo-text-dotnet.svg'> <h1>Iron Software</h1>"; // Start multiple tasks to add watermarks concurrently. tasks[i] = AddWatermarkAsync(inputPath, outputPath, watermarkText, i); } await Task.WhenAll(tasks); // Wait for all tasks to finish. } static async Task AddWatermarkAsync(string input, string outputPath, string watermark, int taskId) { Console.WriteLine($"{DateTime.Now:HH:mm:ss} - Task {taskId} is waiting to add a watermark..."); // Wait to enter the semaphore. await _semaphore.WaitAsync(); try { Console.WriteLine($"{DateTime.Now:HH:mm:ss} - Task {taskId} is adding a watermark."); var pdf = PdfDocument.FromFile(input); pdf.ApplyWatermark(watermark); // Add watermark pdf.SaveAs(outputPath); // Save the modified PDF Console.WriteLine($"{DateTime.Now:HH:mm:ss} - Task {taskId} has completed watermarking."); } finally { // Release the semaphore after the task is done. _semaphore.Release(); Console.WriteLine($"{DateTime.Now:HH:mm:ss} - Task {taskId} has released semaphore."); } } } using IronPdf; using System; using System.Threading; using System.Threading.Tasks; class Program { private static SemaphoreSlim _semaphore = new SemaphoreSlim(1); static async Task Main(string[] args) { // Setting array of tasks var tasks = new Task[3]; for (int i = 0; i < tasks.Length; i++) { string inputPath = $"input_{i}.pdf"; // Input PDF file path string outputPath = $"output_{i}.pdf"; // Output PDF file path string watermarkText = @" <img src='https://ironsoftware.com/img/products/ironpdf-logo-text-dotnet.svg'> <h1>Iron Software</h1>"; // Start multiple tasks to add watermarks concurrently. tasks[i] = AddWatermarkAsync(inputPath, outputPath, watermarkText, i); } await Task.WhenAll(tasks); // Wait for all tasks to finish. } static async Task AddWatermarkAsync(string input, string outputPath, string watermark, int taskId) { Console.WriteLine($"{DateTime.Now:HH:mm:ss} - Task {taskId} is waiting to add a watermark..."); // Wait to enter the semaphore. await _semaphore.WaitAsync(); try { Console.WriteLine($"{DateTime.Now:HH:mm:ss} - Task {taskId} is adding a watermark."); var pdf = PdfDocument.FromFile(input); pdf.ApplyWatermark(watermark); // Add watermark pdf.SaveAs(outputPath); // Save the modified PDF Console.WriteLine($"{DateTime.Now:HH:mm:ss} - Task {taskId} has completed watermarking."); } finally { // Release the semaphore after the task is done. _semaphore.Release(); Console.WriteLine($"{DateTime.Now:HH:mm:ss} - Task {taskId} has released semaphore."); } } } Imports IronPdf Imports System Imports System.Threading Imports System.Threading.Tasks Friend Class Program Private Shared _semaphore As New SemaphoreSlim(1) Shared Async Function Main(ByVal args() As String) As Task ' Setting array of tasks Dim tasks = New Task(2){} For i As Integer = 0 To tasks.Length - 1 Dim inputPath As String = $"input_{i}.pdf" ' Input PDF file path Dim outputPath As String = $"output_{i}.pdf" ' Output PDF file path Dim watermarkText As String = " <img src='https://ironsoftware.com/img/products/ironpdf-logo-text-dotnet.svg'> <h1>Iron Software</h1>" ' Start multiple tasks to add watermarks concurrently. tasks(i) = AddWatermarkAsync(inputPath, outputPath, watermarkText, i) Next i Await Task.WhenAll(tasks) ' Wait for all tasks to finish. End Function Private Shared Async Function AddWatermarkAsync(ByVal input As String, ByVal outputPath As String, ByVal watermark As String, ByVal taskId As Integer) As Task Console.WriteLine($"{DateTime.Now:HH:mm:ss} - Task {taskId} is waiting to add a watermark...") ' Wait to enter the semaphore. Await _semaphore.WaitAsync() Try Console.WriteLine($"{DateTime.Now:HH:mm:ss} - Task {taskId} is adding a watermark.") Dim pdf = PdfDocument.FromFile(input) pdf.ApplyWatermark(watermark) ' Add watermark pdf.SaveAs(outputPath) ' Save the modified PDF Console.WriteLine($"{DateTime.Now:HH:mm:ss} - Task {taskId} has completed watermarking.") Finally ' Release the semaphore after the task is done. _semaphore.Release() Console.WriteLine($"{DateTime.Now:HH:mm:ss} - Task {taskId} has released semaphore.") End Try End Function End Class $vbLabelText $csharpLabel 通過使用 private static SemaphoreSlim _semaphore = new SemaphoreSlim(1); 將信號量計數設置為 1,我們確保每次只有一個任務可以操作 PDF。 控制台輸出 利用 SemaphoreSlim 和 IronPDF 優化性能 管理資源密集型操作 IronPDF 在處理資源密集型任務(如將大型 HTML 文件轉換為 PDF)時表現出色,並且在異步環境中出色地完成這些任務。 使用 SemaphoreSlim 管理這些操作可確保您的應用程序在重負載下保持響應速度,而不會降低性能。 以下示例代碼演示了一種場景,其中我們需要限制並發的大型 HTML 到 PDF 轉換數量,以免系統資源負擔過重。 using IronPdf; using System; using System.Threading; using System.Threading.Tasks; class Program { // Limit concurrent large PDF conversions to 2. private static SemaphoreSlim _semaphore = new SemaphoreSlim(2); static async Task Main(string[] args) { var tasks = new Task[4]; for (int i = 0; i < tasks.Length; i++) { string htmlContent = $"<h1>Large Document {i}</h1><p>Content for a large HTML file {i}.</p>"; string outputPath = $"large_output_{i}.pdf"; // Start multiple tasks to convert large HTML files to PDFs. tasks[i] = ConvertLargeHtmlAsync(htmlContent, outputPath, i); } await Task.WhenAll(tasks); // Wait for all tasks to finish. } // Method to convert large HTML to PDF using SemaphoreSlim to control resource usage. public static async Task ConvertLargeHtmlAsync(string htmlContent, string outputPath, int taskId) { Console.WriteLine($"Task {taskId} is waiting to start conversion..."); // Wait to enter the semaphore. await _semaphore.WaitAsync(); try { Console.WriteLine($"Task {taskId} is converting large HTML to PDF."); var renderer = new ChromePdfRenderer(); var pdf = await renderer.RenderHtmlAsPdfAsync(htmlContent); // Convert large HTML to PDF pdf.SaveAs(outputPath); // Save the PDF file Console.WriteLine($"Task {taskId} has completed conversion."); } finally { // Ensure the semaphore is released to allow other tasks to proceed. _semaphore.Release(); Console.WriteLine($"Task {taskId} has released semaphore."); } } } using IronPdf; using System; using System.Threading; using System.Threading.Tasks; class Program { // Limit concurrent large PDF conversions to 2. private static SemaphoreSlim _semaphore = new SemaphoreSlim(2); static async Task Main(string[] args) { var tasks = new Task[4]; for (int i = 0; i < tasks.Length; i++) { string htmlContent = $"<h1>Large Document {i}</h1><p>Content for a large HTML file {i}.</p>"; string outputPath = $"large_output_{i}.pdf"; // Start multiple tasks to convert large HTML files to PDFs. tasks[i] = ConvertLargeHtmlAsync(htmlContent, outputPath, i); } await Task.WhenAll(tasks); // Wait for all tasks to finish. } // Method to convert large HTML to PDF using SemaphoreSlim to control resource usage. public static async Task ConvertLargeHtmlAsync(string htmlContent, string outputPath, int taskId) { Console.WriteLine($"Task {taskId} is waiting to start conversion..."); // Wait to enter the semaphore. await _semaphore.WaitAsync(); try { Console.WriteLine($"Task {taskId} is converting large HTML to PDF."); var renderer = new ChromePdfRenderer(); var pdf = await renderer.RenderHtmlAsPdfAsync(htmlContent); // Convert large HTML to PDF pdf.SaveAs(outputPath); // Save the PDF file Console.WriteLine($"Task {taskId} has completed conversion."); } finally { // Ensure the semaphore is released to allow other tasks to proceed. _semaphore.Release(); Console.WriteLine($"Task {taskId} has released semaphore."); } } } Imports IronPdf Imports System Imports System.Threading Imports System.Threading.Tasks Friend Class Program ' Limit concurrent large PDF conversions to 2. Private Shared _semaphore As New SemaphoreSlim(2) Shared Async Function Main(ByVal args() As String) As Task Dim tasks = New Task(3){} For i As Integer = 0 To tasks.Length - 1 Dim htmlContent As String = $"<h1>Large Document {i}</h1><p>Content for a large HTML file {i}.</p>" Dim outputPath As String = $"large_output_{i}.pdf" ' Start multiple tasks to convert large HTML files to PDFs. tasks(i) = ConvertLargeHtmlAsync(htmlContent, outputPath, i) Next i Await Task.WhenAll(tasks) ' Wait for all tasks to finish. End Function ' Method to convert large HTML to PDF using SemaphoreSlim to control resource usage. Public Shared Async Function ConvertLargeHtmlAsync(ByVal htmlContent As String, ByVal outputPath As String, ByVal taskId As Integer) As Task Console.WriteLine($"Task {taskId} is waiting to start conversion...") ' Wait to enter the semaphore. Await _semaphore.WaitAsync() Try Console.WriteLine($"Task {taskId} is converting large HTML to PDF.") Dim renderer = New ChromePdfRenderer() Dim pdf = Await renderer.RenderHtmlAsPdfAsync(htmlContent) ' Convert large HTML to PDF pdf.SaveAs(outputPath) ' Save the PDF file Console.WriteLine($"Task {taskId} has completed conversion.") Finally ' Ensure the semaphore is released to allow other tasks to proceed. _semaphore.Release() Console.WriteLine($"Task {taskId} has released semaphore.") End Try End Function End Class $vbLabelText $csharpLabel 在處理資源密集型任務(例如將大型 HTML 文件轉換為 PDF)時,SemaphoreSlim 可以幫助平衡負載並優化資源使用。 通過設置 2 次並發操作的限制,我們防止系統被資源密集型 PDF 生成任務壓倒。 此方法有助於更均勻地分配工作負載,提高整體應用程序性能和穩定性。 輸出圖像:使用此方法生成的文件 避免並發管理中的死鎖 如果信號量未正確釋放,則可能發生死鎖。 需要記住的一個好的實踐是使用 try-finally 塊來確保即使發生異常也能釋放信號量,從而防止死鎖並保持您的應用程序平穩運行。 避免死鎖的一些最佳實踐包括始終在 finally 塊中釋放信號量,並避免在異步代碼中使用阻塞調用,如 Wait() 和 Result。 using IronPdf; using System; using System.Threading; using System.Threading.Tasks; class Program { private static SemaphoreSlim _semaphore = new SemaphoreSlim(3); static async Task Main(string[] args) { var tasks = new Task[3]; for (int i = 0; i < tasks.Length; i++) { string content = $"<h1>Document {i}</h1><p>Content for PDF {i}.</p>"; string path = $"safe_output_{i}.pdf"; // Start multiple tasks to demonstrate deadlock-free semaphore usage. tasks[i] = SafePdfTaskAsync(content, path, i); } await Task.WhenAll(tasks); // Wait for all tasks to finish. } // Method demonstrating best practices for using SemaphoreSlim to avoid deadlocks. public static async Task SafePdfTaskAsync(string content, string path, int taskId) { Console.WriteLine($"Task {taskId} is waiting to generate PDF..."); // Wait to enter the semaphore. await _semaphore.WaitAsync(); try { Console.WriteLine($"Task {taskId} is generating PDF."); var renderer = new ChromePdfRenderer(); var pdf = await renderer.RenderHtmlAsPdfAsync(content); // Render HTML to PDF pdf.SaveAs(path); // Save the PDF Console.WriteLine($"Task {taskId} has completed PDF generation."); } catch (Exception ex) { Console.WriteLine($"Task {taskId} encountered an error: {ex.Message}"); } finally { // Always release the semaphore, even if an error occurs. _semaphore.Release(); Console.WriteLine($"Task {taskId} has released semaphore."); } } } using IronPdf; using System; using System.Threading; using System.Threading.Tasks; class Program { private static SemaphoreSlim _semaphore = new SemaphoreSlim(3); static async Task Main(string[] args) { var tasks = new Task[3]; for (int i = 0; i < tasks.Length; i++) { string content = $"<h1>Document {i}</h1><p>Content for PDF {i}.</p>"; string path = $"safe_output_{i}.pdf"; // Start multiple tasks to demonstrate deadlock-free semaphore usage. tasks[i] = SafePdfTaskAsync(content, path, i); } await Task.WhenAll(tasks); // Wait for all tasks to finish. } // Method demonstrating best practices for using SemaphoreSlim to avoid deadlocks. public static async Task SafePdfTaskAsync(string content, string path, int taskId) { Console.WriteLine($"Task {taskId} is waiting to generate PDF..."); // Wait to enter the semaphore. await _semaphore.WaitAsync(); try { Console.WriteLine($"Task {taskId} is generating PDF."); var renderer = new ChromePdfRenderer(); var pdf = await renderer.RenderHtmlAsPdfAsync(content); // Render HTML to PDF pdf.SaveAs(path); // Save the PDF Console.WriteLine($"Task {taskId} has completed PDF generation."); } catch (Exception ex) { Console.WriteLine($"Task {taskId} encountered an error: {ex.Message}"); } finally { // Always release the semaphore, even if an error occurs. _semaphore.Release(); Console.WriteLine($"Task {taskId} has released semaphore."); } } } Imports IronPdf Imports System Imports System.Threading Imports System.Threading.Tasks Friend Class Program Private Shared _semaphore As New SemaphoreSlim(3) Shared Async Function Main(ByVal args() As String) As Task Dim tasks = New Task(2){} For i As Integer = 0 To tasks.Length - 1 Dim content As String = $"<h1>Document {i}</h1><p>Content for PDF {i}.</p>" Dim path As String = $"safe_output_{i}.pdf" ' Start multiple tasks to demonstrate deadlock-free semaphore usage. tasks(i) = SafePdfTaskAsync(content, path, i) Next i Await Task.WhenAll(tasks) ' Wait for all tasks to finish. End Function ' Method demonstrating best practices for using SemaphoreSlim to avoid deadlocks. Public Shared Async Function SafePdfTaskAsync(ByVal content As String, ByVal path As String, ByVal taskId As Integer) As Task Console.WriteLine($"Task {taskId} is waiting to generate PDF...") ' Wait to enter the semaphore. Await _semaphore.WaitAsync() Try Console.WriteLine($"Task {taskId} is generating PDF.") Dim renderer = New ChromePdfRenderer() Dim pdf = Await renderer.RenderHtmlAsPdfAsync(content) ' Render HTML to PDF pdf.SaveAs(path) ' Save the PDF Console.WriteLine($"Task {taskId} has completed PDF generation.") Catch ex As Exception Console.WriteLine($"Task {taskId} encountered an error: {ex.Message}") Finally ' Always release the semaphore, even if an error occurs. _semaphore.Release() Console.WriteLine($"Task {taskId} has released semaphore.") End Try End Function End Class $vbLabelText $csharpLabel 通過使用 try-catch-finally 塊,我們確保即使拋出異常也能始終釋放 SemaphoreSlim 對象,從而防止死鎖。 通過記錄錯誤和正確管理信號量釋放,我們可以保持程序穩定,防止任何意外行為。 正如您在下圖中所看到的,我通過嘗試讓程序加載不存在的 HTML 文件來模擬錯誤,但即使發生此錯誤,程序也會輸出錯誤信息,告訴我出了什麼問題,然後使用 finally 塊釋放信號量。 使用 IronPDF 進行並發 PDF 處理的好處 高效可靠的 PDF 處理 IronPDF 被設計為能夠高效地處理並發 PDF 處理任務,其性能和可靠性優於許多其他 PDF 庫。 其穩健的架構使其能夠根據您的應用程序需求進行擴展,非常適合高要求的環境。 基於性能、易用性和穩健性標準,IronPDF 與其他 PDF 庫相比,一直是強有力的競爭對手。 為了展示這一點,我將 IronPDF 與其他幾個流行的 PDF 庫(如 iTextSharp、PDFsharp、DinkToPdf 和 EvoPDF)進行了比較: 1. 性能 IronPDF: 渲染速度:IronPDF 以其快速高效的渲染能力而聞名,特別是在將 HTML 轉換為 PDF 時。 它使用基於 Chrome 的渲染,提供對原始 HTML 內容的高度忠實度,包括 CSS 和 JavaScript 執行。 資源管理:IronPDF 在處理大型且復雜的 PDF 時的內存使用量較低,與其他庫相比,適合高容量應用。 異步操作:支持異步 PDF 生成,允許在注重響應性的 Web 應用中進一步提高性能。 iTextSharp: 渲染速度:iTextSharp 在以文字為主的 PDF 中提供良好的性能,但在處理複雜的布局或圖像時可能顯著變慢。 資源管理:內存使用量可能較高,尤其是在處理大型文檔或複雜操作時,這可能在某些情況下導致性能瓶頸。 PDFsharp: 渲染速度:在處理複雜布局或從 HTML 轉換時,PDFsharp 通常比 IronPDF 慢,因為它缺乏本地 HTML 渲染引擎。 資源管理:在內存使用上不太優化,處理大型文件或包含大量圖像的文檔時可能會遇到困難。 DinkToPdf: 渲染速度:DinkToPdf 使用 wkhtmltopdf 引擎,適合基礎的 HTML 到 PDF 轉換,但在處理較複雜或動態內容時可能困難。 資源管理:通常需要大量的內存和處理能力,且缺乏原生的異步操作支持,限制其在高負載場景中的性能。 EvoPDF: 渲染速度:EvoPDF 同樣提供基於 Chrome 的渲染,與 IronPDF 類似,特別是在 HTML 到 PDF 轉換方面提供了良好的性能。 資源管理:其優化程度較高,但在某些情況下,由於優化不足,可能與 IronPDF 比較消耗資源。 2. 易用性 IronPDF: API 設計:IronPDF 提供一個現代、直觀的 API,對各技能水平的開發者來說都易於使用。 該庫設計為無縫地與 .NET 應用程序協同工作,這使得它成為 C# 開發人員的絕佳選擇。 文檔和支持:全面的文檔、大量代碼示例以及出色的客戶支持使其易於入門並快速解決問題。 安裝和集成:可通過 NuGet 方便地安裝,並可順利集成到現有的 .NET 項目中,所需的配置非常少。 iTextSharp: API 設計:iTextSharp的學習曲線陡峭,API 相對較為複雜,對初學者來說可能讓人不知所措。 其靈活性犧牲了簡單性。 文檔和支持:雖然文檔齊全,但廣泛的配置選項可能使得尋找常見任務的簡單示例變得困難。 安裝和集成:可通過 NuGet 使用,但需要更深入地了解 API 才能有效集成。 PDFsharp: API 設計:PDFsharp 設計為對基本 PDF 任務而言簡單,但缺乏開箱即用的高級功能,這可能會限制其在更複雜場景中的使用。 文檔和支持:提供了基本文檔,但與 IronPDF 相比,缺乏廣泛的例子和詳細的高級使用案例說明。 安裝和集成:通過 NuGet 易於安裝,但對 HTML 到 PDF 的功能有限。 DinkToPdf: API 設計:DinkToPdf 的 API 相對簡單,但相比於 IronPDF 不夠完善。 它主要對準 HTML 到 PDF 的轉換,對直接 PDF 操作功能較少。 文檔和支持:文檔有限,社區支持不如其他庫,從而使得故障排除更具挑戰性。 安裝和集成:安裝可能更加複雜,需額外依賴 kuten wkhtmltopdf,這可能會使設置變得複雜。 EvoPDF: API 設計:EvoPDF 提供了一個與 IronPDF 相似的簡單 API,專注於 HTML 到 PDF 的轉換。 文檔和支持:文檔完善且支持優良,但在社區驅動的例子方面不如 IronPDF 廣泛。 安裝和集成:通過 NuGet 輕鬆集成到 .NET 項目中。 3. 穩健性 IronPDF: 特徵集:IronPDF 非常穩健,支持各種功能,包括 HTML 到 PDF 轉換、PDF 編輯、文本提取、加密、註釋和數位簽名。 錯誤處理:提供強大的錯誤處理和異常管理,使其在生產環境中可靠。 兼容性:完全兼容於 .NET Core、.NET 5+ 和傳統的 .NET Framework 版本,使其在各類項目中通用。 iTextSharp: 特徵集:iTextSharp 擁有非常穩健和完善的特徵集,幾乎支持每一種 PDF 任務,包括複雜的操作和表單處理。 錯誤處理:良好的錯誤處理,但由於庫的複雜性,管理起來可能較困難。 兼容性:適合於各種環境,包括 .NET Framework 和 .NET Core。 PDFsharp: 特徵集:基本的 PDF 創建和操作特性。 缺乏一些高級功能,如HTML到PDF的轉換和更高級的文件編輯功能。 錯誤處理:基本的錯誤處理; 與更多的穩健庫如 IronPDF 相比,在複雜場景中較不可靠。 兼容性:兼容於 .NET Framework 和 .NET Core,但高級功能有限。 DinkToPdf: 特徵集:主要專注於HTML到PDF。 在直接的 PDF 操作方面有限,缺乏高級功能如註解和表單處理。 錯誤處理:基本的錯誤處理; 對於複雜 HTML 或大型文件,容易崩潰或卡住。 兼容性:在 .NET Core 和 .NET 框架中均可工作,但需要額外的依賴,這可能帶來兼容性問題。 EvoPDF: 特徵集:提供了一個與 IronPDF 相似的強大特徵集,包括高級 HTML 到 PDF 的轉換和一些文檔操作功能。 錯誤處理:穩定的錯誤處理和在生產環境中的可靠性能。 兼容性:完全兼容最新版的 .NET Core、.NET Framework 和更高版本,讓它非常多用途。 總結 性能:得益於基於 Chrome 的渲染引擎,IronPDF 和 EvoPDF 的性能屬於領先,而 iTextSharp 和 PDFsharp 在處理複雜文檔時可能會落後。 易用性:憑藉其直觀的 API 和廣泛的文檔,使得 IronPDF 對所有級別的開發者來說輕而易舉。 iTextSharp 以強大著稱,但卻犧牲了簡單性,而 DinkToPdf 和 PDFsharp 較為容易,但功能較少。 穩健性:IronPDF 和 iTextSharp 提供了最為穩健的特徵集,其中 IronPDF 提供更簡單的整合和現代功能(如異步支持),而 iTextSharp 通過更陡峭的學習曲線涵蓋了更多的細分用例。 對於異步程序的全面支持 IronPDF 無縫集成了 異步程序模型,補足了如 SemaphoreSlim 這樣的並發控制機制。 這使得開發者能夠輕鬆構建出響應性良好且性能友好的應用程序。 IronPDF 也提供了豐富的文檔和支持資源,幫助開發者了解和實現有效的錯誤處理實踐。 這些全面支持對於 .NET 項目中的 PDF 操作優化和故障排查非常有價值。 IronPDF 提供了: 綜合文檔:覆蓋所有功能的豐富易用的文檔。 24/5 支持:提供積極的工程支持。 視頻教程:在 YouTube 上可以找到按步驟操作的視頻指南。 社區論壇:活躍的社群可提供額外的支持。 PDF API參考:提供 API 參考,以便獲得我們工具的最佳效益。 如需了解更多信息,請查閱 IronPDF 的豐富文檔。 結論 在 .NET 應用程式中使用 SemaphoreSlim 進行並發管理至關重要,特別是在處理像 PDF 處理這樣的資源密集型任務時。 通過將 SemaphoreSlim 與 IronPDF 集成,開發人員可以實現安全、高效和可靠的並發控制,確保其應用保持響應和性能友好。 發現 IronPDF 如何簡化您的 PDF 處理工作流程。 您可以親自試用其免費試用,如果要在項目中保持使用這個強大的工具,只需從$799 開始。 常見問題解答 SemaphoreSlim在併發管理中的作用是什麼? SemaphoreSlim在併發管理中起著至關重要的作用,通過限制同時可以訪問特定資源的線程數來控制併發,這種控制有助於防止競賽條件並確保線程安全,特別是在與IronPDF等庫集成以生成PDF時。 如何將SemaphoreSlim與PDF庫集成以提高性能? 可以將SemaphoreSlim與IronPDF集成以管理並發PDF生成任務的數量。通過這樣做,可以防止性能下降並確保線程同步,從而實現高效的PDF處理。 使用SemaphoreSlim與異步編程的優勢有哪些? SemaphoreSlim支持異步等待方法,使其非常適合於異步編程模型。該兼容性允許進行響應式應用程序開發,特別是在使用IronPDF生成和操作多線程環境中的PDF時。 SemaphoreSlim如何增強C#應用程序中的PDF生成? SemaphoreSlim通過確保只有指定數量的線程可以同時訪問PDF生成任務來增強PDF生成。這種受控訪問可防止系統過載並優化IronPDF在C#應用程序中的性能。 多線程PDF生成的一些常見問題是什麼,它們如何可以避免? 常見問題包括競爭條件和死鎖。通過使用SemaphoreSlim與IronPDF,可以限制並發線程數,從而避免競爭條件。此外,確保信號燈適當釋放以防止死鎖。 SemaphoreSlim可以提高並發PDF處理的可靠性嗎? 可以,通過使用SemaphoreSlim與IronPDF,你可以控制同時處理PDF的線程數,從而在多線程環境中增強可靠性和一致性。 與其他庫相比,IronPDF的穩健性來源於什麼? IronPDF被認為很穩健源於其快速的基於Chrome的渲染引擎、易於使用、豐富的文檔,以及與異步編程模型的無縫集成,使其優於iTextSharp和EvoPDF等庫。 開發者如何學習更多有關SemaphoreSlim和IronPDF的集成? 開發者可以探索IronPDF提供的全麵文檔,其中包括詳細指南、API參考和教程。這些信息結合SemaphoreSlim資源,可以輔助有效地將它們一起實施。 Curtis Chau 立即與工程團隊聊天 技術作家 Curtis Chau 擁有卡爾頓大學計算機科學學士學位,專注於前端開發,擅長於 Node.js、TypeScript、JavaScript 和 React。Curtis 熱衷於創建直觀且美觀的用戶界面,喜歡使用現代框架並打造結構良好、視覺吸引人的手冊。除了開發之外,Curtis 對物聯網 (IoT) 有著濃厚的興趣,探索將硬體和軟體結合的創新方式。在閒暇時間,他喜愛遊戲並構建 Discord 機器人,結合科技與創意的樂趣。 相關文章 更新日期 9月 4, 2025 RandomNumberGenerator C# 使用RandomNumberGenerator C#類可以幫助將您的PDF生成和編輯項目提升至新水準 閱讀更多 更新日期 9月 4, 2025 C#字符串等於(它如何對開發者起作用) 當結合使用強大的PDF庫IronPDF時,開關模式匹配可以讓您構建更智能、更清晰的邏輯來進行文檔處理 閱讀更多 更新日期 8月 5, 2025 C#開關模式匹配(對開發者來說是如何工作的) 當結合使用強大的PDF庫IronPDF時,開關模式匹配可以讓您構建更智能、更清晰的邏輯來進行文檔處理 閱讀更多 C#初始化關鍵字(對開發者如何理解的工作)C#嘗試-捕捉-最終區塊(對...