跳至頁尾內容
.NET 幫助

C# 並發清單(開發者如何理解其工作原理)

如果您曾經讓多個線程爭奪共用資源的存取權,您就會知道線程安全的實作並不是遊戲。 不過不用擔心! C# 已為您提供並發集合 - 一套功能強大的線程安全、泛型集合類別,可確保線程安全,且風格優雅。

C# 中的線程安全與並發集合;

讓我們先想像一個沒有紅綠燈的熱鬧城市十字路口。 您可以想像當時的混亂情況! 這類似於當多個線程同時訪問共享資源而沒有適當的系統時發生的情況。 值得慶幸的是,在 C# 中,我們的線程有交通燈 - 這些稱為並發集合。 它們是集合類別,一次只允許一個線程存取資源。當使用多個線程工作時,這種線程安全性是至關重要的。

探索 C# 中的並發線程安全集合;

在 C# 中,命名空間 System.Collections.Concurrent 包含多種並發集合類別,例如 ConcurrentDictionary, ConcurrentQueue, ConcurrentStack 以及 ConcurrentBag 。 這些無序集合類別提供了其非並行對應類型的線程安全版本。 並發集合的與眾不同之處在於它們是無序的並發集合,這意味著元素沒有特定的順序。 舉例來說,對於並發清單,您無法確切知道項目插入的位置。 重點在於確保線程安全,而非維持秩序。

讓我們舉一個真實的例子。 想想網站的密碼提交貼文。透過並發集合,多位使用者可以同時提交密碼。 每個"提交"動作就像一個線程,並發集合可確保每個提交都是線程安全、處理安全且有效率的。

ConcurrentDictionary:真實世界的範例

現在,讓我們以實際的範例來探討 ConcurrentDictionary 集合類別。 想像一個具有推薦功能的線上書店。 使用者的每次點選都會將一本書加入個人推薦清單,並以字典為代表。 由於有多位使用者同時瀏覽和點選書籍,因此我們有多個線程同時存取字典。

C# 中的 ConcurrentDictionary 應該是這樣的:

using System.Collections.Concurrent;

ConcurrentDictionary<string, string> recommendedBooks = new ConcurrentDictionary<string, string>();
using System.Collections.Concurrent;

ConcurrentDictionary<string, string> recommendedBooks = new ConcurrentDictionary<string, string>();
$vbLabelText   $csharpLabel

若要將書籍加入使用者的整個推薦集合,我們可以使用 TryAdd 方法:

public void Insert(string user, string book)
{
    // Try to add the book to the user's recommendations
    recommendedBooks.TryAdd(user, book);
}
public void Insert(string user, string book)
{
    // Try to add the book to the user's recommendations
    recommendedBooks.TryAdd(user, book);
}
$vbLabelText   $csharpLabel

在此情境中,ConcurrentDictionary 集合類別可確保每次點選(或稱為"線程")都會單獨處理,因此不會混淆兩個使用者的建議。它會處理所有的線程安全,因此您不必擔心資料競賽以及其他與多線程相關聯的並發問題。

實現線程安全作業

除了 TryAdd 之外,C# 中的並發集合提供了多種其他線程安全的操作,例如 TryRemoveTryUpdate 。 這些方法可確保一次只能有一個線程執行操作。因此,舉例來說,如果我們想要從上一個範例中的使用者推薦中移除一本书,我們可以使用 TryRemove 方法:

public void RemoveAt(string user)
{
    // Attempt to remove the book for the specified user
    string removedBook;
    recommendedBooks.TryRemove(user, out removedBook);
}
public void RemoveAt(string user)
{
    // Attempt to remove the book for the specified user
    string removedBook;
    recommendedBooks.TryRemove(user, out removedBook);
}
$vbLabelText   $csharpLabel

TryRemove 方法將嘗試移除所提供的關鍵值 (在本例中為使用者),並將其放入 removedBook 變數中。

複製並發集合

現在,假設您想要將您的並發集合複製到陣列中。 Concurrent 集合提供了一個 CopyTo 方法,正是為了這個目的:

public void CopyTo()
{
    // Create an array to hold the recommended books
    string[] bookArray = new string[recommendedBooks.Count];

    // Copy the values of the concurrent dictionary to the array
    recommendedBooks.Values.CopyTo(bookArray, 0);
}
public void CopyTo()
{
    // Create an array to hold the recommended books
    string[] bookArray = new string[recommendedBooks.Count];

    // Copy the values of the concurrent dictionary to the array
    recommendedBooks.Values.CopyTo(bookArray, 0);
}
$vbLabelText   $csharpLabel

在此,CopyTo 方法會將 recommendedBooks 並發字典中的所有書籍 (值) 複製到 bookArray 中。

線程安全收集

C# 也提供 thread-safe 集合,其目的是確保在多執行緒環境中安全存取共用資源。 這些集合(例如 ConcurrentBagConcurrentQueueConcurrentStack)提供線程安全的實作,多個線程可以同時存取和修改集合,而不會造成衝突或資料損毀。

這些工具透過內部處理同步化來保證一致性和完整性,因此非常適用於無序集合已足夠的情況,而線程安全在您的 C# 應用程式中是最重要的。

瞭解更多關於 IronPDF 是一個廣受歡迎的 C# 函式庫,可讓您毫不費力地從 HTML 產生 PDF 文件

using IronPdf;

class Program
{
    static void Main(string[] args)
    {
        var renderer = new ChromePdfRenderer();

        // 1. Convert HTML String to PDF
        var htmlContent = "<h1>Hello, IronPDF!</h1><p>This is a PDF from an HTML string.</p>";
        var pdfFromHtmlString = renderer.RenderHtmlAsPdf(htmlContent);
        pdfFromHtmlString.SaveAs("HTMLStringToPDF.pdf");

        // 2. Convert HTML File to PDF
        var htmlFilePath = "path_to_your_html_file.html"; // Specify the path to your HTML file
        var pdfFromHtmlFile = renderer.RenderHtmlFileAsPdf(htmlFilePath);
        pdfFromHtmlFile.SaveAs("HTMLFileToPDF.pdf");

        // 3. Convert URL to PDF
        var url = "http://ironpdf.com"; // Specify the URL
        var pdfFromUrl = renderer.RenderUrlAsPdf(url);
        pdfFromUrl.SaveAs("URLToPDF.pdf");
    }
}
using IronPdf;

class Program
{
    static void Main(string[] args)
    {
        var renderer = new ChromePdfRenderer();

        // 1. Convert HTML String to PDF
        var htmlContent = "<h1>Hello, IronPDF!</h1><p>This is a PDF from an HTML string.</p>";
        var pdfFromHtmlString = renderer.RenderHtmlAsPdf(htmlContent);
        pdfFromHtmlString.SaveAs("HTMLStringToPDF.pdf");

        // 2. Convert HTML File to PDF
        var htmlFilePath = "path_to_your_html_file.html"; // Specify the path to your HTML file
        var pdfFromHtmlFile = renderer.RenderHtmlFileAsPdf(htmlFilePath);
        pdfFromHtmlFile.SaveAs("HTMLFileToPDF.pdf");

        // 3. Convert URL to PDF
        var url = "http://ironpdf.com"; // Specify the URL
        var pdfFromUrl = renderer.RenderUrlAsPdf(url);
        pdfFromUrl.SaveAs("URLToPDF.pdf");
    }
}
$vbLabelText   $csharpLabel

儘管 IronPDF 一開始似乎與並發清單沒有直接關係,但它可以輔助您的並發收集作業,提供簡易的方式來建立 PDF 報告、日誌或任何其他可擷取您的並發處理結果的文件。

考慮您有一個執行密集資料處理的多執行緒應用程式的情況。 當線程在資料上發揮魔力時,您可能想要擷取結果並產生 PDF 報告,以便進一步分析或記錄。 這就是 IronPdf 發揮作用的地方。

使用 IronPDF 非常簡單,只需將函式庫新增至您的專案,並使用其便利的 API 即可。 以下是如何將 IronPDF 與您的並發收集作業整合的範例:

using IronPdf;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading.Tasks;

// Create a concurrent dictionary to hold your processed data
ConcurrentDictionary<int, string> processedData = new ConcurrentDictionary<int, string>();

// Define your data list (replace with your actual data source)
List<DataItem> dataList = GetDataList();

// Process your data concurrently and store the results in the dictionary
Parallel.ForEach(dataList, (dataItem) =>
{
    // Process each data item and add the result to the dictionary
    string processedResult = ProcessDataItem(dataItem);
    processedData.TryAdd(dataItem.Id, processedResult);
});

// Generate a PDF report with the processed data
var renderer = new ChromePdfRenderer();
var pdfDocument = renderer.RenderHtmlAsPdf(BuildHtmlReport(processedData));
pdfDocument.SaveAs("C:\\processed_data_report.pdf");

// Method to retrieve the data list (replace with your actual data source logic)
List<DataItem> GetDataList()
{
    List<DataItem> dataList = new List<DataItem>()
    {
        new DataItem { Id = 1, Name = "Item 1" },
        new DataItem { Id = 2, Name = "Item 2" },
        new DataItem { Id = 3, Name = "Item 3" },
        new DataItem { Id = 4, Name = "Item 4" }
    };
    return dataList;
}

// Method to process each data item and return the result (replace with your actual data processing logic)
string ProcessDataItem(DataItem dataItem)
{
    // Simulating data processing with a delay
    Task.Delay(100).Wait();
    return $"Processed: {dataItem.Name}";
}

// Method to build the HTML report using the processed data (replace with your actual reporting logic)
string BuildHtmlReport(ConcurrentDictionary<int, string> processedData)
{
    string html = "<h1>Processed Data Report</h1><ul>";
    foreach (var kvp in processedData)
    {
        html += $"<li>Item {kvp.Key}: {kvp.Value}</li>";
    }
    html += "</ul>";
    return html;
}

// Placeholder class for your data item (replace with your actual data item class)
public class DataItem
{
    public int Id { get; set; }
    public string Name { get; set; }
    // Add other properties as needed
}
using IronPdf;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading.Tasks;

// Create a concurrent dictionary to hold your processed data
ConcurrentDictionary<int, string> processedData = new ConcurrentDictionary<int, string>();

// Define your data list (replace with your actual data source)
List<DataItem> dataList = GetDataList();

// Process your data concurrently and store the results in the dictionary
Parallel.ForEach(dataList, (dataItem) =>
{
    // Process each data item and add the result to the dictionary
    string processedResult = ProcessDataItem(dataItem);
    processedData.TryAdd(dataItem.Id, processedResult);
});

// Generate a PDF report with the processed data
var renderer = new ChromePdfRenderer();
var pdfDocument = renderer.RenderHtmlAsPdf(BuildHtmlReport(processedData));
pdfDocument.SaveAs("C:\\processed_data_report.pdf");

// Method to retrieve the data list (replace with your actual data source logic)
List<DataItem> GetDataList()
{
    List<DataItem> dataList = new List<DataItem>()
    {
        new DataItem { Id = 1, Name = "Item 1" },
        new DataItem { Id = 2, Name = "Item 2" },
        new DataItem { Id = 3, Name = "Item 3" },
        new DataItem { Id = 4, Name = "Item 4" }
    };
    return dataList;
}

// Method to process each data item and return the result (replace with your actual data processing logic)
string ProcessDataItem(DataItem dataItem)
{
    // Simulating data processing with a delay
    Task.Delay(100).Wait();
    return $"Processed: {dataItem.Name}";
}

// Method to build the HTML report using the processed data (replace with your actual reporting logic)
string BuildHtmlReport(ConcurrentDictionary<int, string> processedData)
{
    string html = "<h1>Processed Data Report</h1><ul>";
    foreach (var kvp in processedData)
    {
        html += $"<li>Item {kvp.Key}: {kvp.Value}</li>";
    }
    html += "</ul>";
    return html;
}

// Placeholder class for your data item (replace with your actual data item class)
public class DataItem
{
    public int Id { get; set; }
    public string Name { get; set; }
    // Add other properties as needed
}
$vbLabelText   $csharpLabel

以下是程式碼的輸出:

C# 並發列表 (How It Works For Developers) 圖 1 - Output

結論

總而言之,瞭解並運用 C# 並發集合(例如並發清單),可以大幅提升您處理多執行緒情境的能力,並確保應用程式中的線程安全。 使用並發集合,您可以有效地管理共用資源,防止資料競賽和線程間的碰撞。

整合 IronPDF 之類的外部函式庫,可以藉由產生視覺上吸引人的 PDF 報告或文件,進一步強化並發集合的功能。 IronPdf 提供 免費試用其 HTML 至 PDF 轉換函式庫,讓您探索其功能,以及 $799 起的授權選項。

常見問題解答

C# 中的並發集合是什麼?

C# 中的並發集合是一套執行緒安全的通用集合類,可確保多個執行緒存取共享資源時的執行緒安全性。

為什麼線程安全在 C# 中很重要?

在 C# 中,執行緒安全至關重要,它可以防止多個執行緒並發存取和修改共享資源時出現混亂和資料損壞。它確保操作以受控的方式執行。

如何在 C# 中建立線程安全的清單?

雖然 C# 沒有直接提供線程安全的 List 類,但您可以使用其他並發集合,例如 `ConcurrentBag` 或 `ConcurrentDictionary`,來實現類似的線程安全操作。

C# 中的 ConcurrentDictionary 是什麼?

C# 中的 ConcurrentDictionary 是 `System.Collections.Concurrent` 命名空間中的一個執行緒安全性集合類別。它允許多個線程安全地並發添加、更新和刪除鍵值對。

ConcurrentDictionary 如何確保線程安全?

ConcurrentDictionary 透過內部處理同步來確保執行緒安全,一次只允許一個執行緒執行新增或刪除項目等操作。

如何為 ConcurrentDictionary 新增項目?

您可以使用TryAdd方法為 ConcurrentDictionary 新增項目,該方法僅在鍵在字典中尚不存在時才嘗試新增鍵值對。

並發集合中的 CopyTo 方法有什麼用途?

並發集合中的 CopyTo 方法用於將集合中的元素複製到陣列中,從而提供了一種將資料從集合傳輸到另一種儲存格式的方法。

IronPDF 能否用於從處理後的數據產生 PDF 報告?

是的,IronPDF 可用於從多執行緒應用程式處理的資料產生 PDF 報告,擷取並發操作的結果。

使用 IronPDF 如何增強並發操作的功能?

IronPDF 透過支援從處理後的資料建立 PDF 文件來增強並發操作,提供了一種記錄和共享多執行緒處理結果的方法。

IronPDF 在多執行緒 C# 應用程式中扮演什麼角色?

IronPDF 讓開發人員可以從平行處理的資料產生 PDF 報告,從而更容易整合和共享多執行緒操作的結果。

Jacob Mellor,Team Iron 首席技術官
首席技術長

Jacob Mellor 是 Iron Software 的首席技術官,也是一位富有遠見的工程師,率先開發了 C# PDF 技術。作為 Iron Software 核心程式碼庫的最初開發者,他自公司成立之初便參與塑造了其產品架構,並與執行長 Cameron Rimington 一起將其發展成為一家擁有 50 多名員工、服務於 NASA、特斯拉和全球政府機構的公司。

Jacob 於 1998 年至 2001 年在曼徹斯特大學獲得土木工程一級榮譽學士學位。 1999 年,他在倫敦創辦了自己的第一家軟體公司;2005 年,他創建了自己的第一個 .NET 元件。此後,他專注於解決微軟生態系統中的複雜問題。

他的旗艦產品 IronPDF 和 IronSuite .NET 庫在全球 NuGet 上的安裝量已超過 3000 萬次,其基礎程式碼持續為全球開發者工具提供支援。憑藉 25 年的商業經驗和 41 年的程式設計專長,Jacob 始終致力於推動企業級 C#、Java 和 Python PDF 技術的創新,同時指導下一代技術領導者。