跳過到頁腳內容
.NET幫助

C# 並發列表(開發者的工作原理)

如果你曾經有多個執行緒競爭共享資源的存取權,你就會知道執行緒安全的實現不是一場遊戲。 不過,不用擔心! C# 提供了併發集合——一組強大的執行緒安全的泛型集合類別,能以風格和優雅確保執行緒安全。

執行緒安全和 C# 的同步集合

讓我們從想像一個繁忙的城市十字路口開始,沒有紅綠燈。 你可以想像那種混亂! 這類似於沒有適當系統設置時,多個執行緒同時存取共享資源的情況。 幸運的是,在 C# 中,我們有給執行緒的交通信號——這些稱為同步集合。 它們是集合類別,允許每次只有一個執行緒存取資源。這種執行緒安全性在處理多個執行緒時至關重要。

探討 C# 中的同步安全集合

在 C# 中,命名空間 System.Collections.Concurrent 有多種同步集合類別,如 ConcurrentDictionaryConcurrentQueueConcurrentStackConcurrentBag。 這些無序集合類別提供了其非同步對應版本的執行緒安全版本。 同步集合的特點是它們是無序的同步集合,這意味著元素沒有特定順序。 例如,在同步列表中,你不知道項目具體插入的位置。 重點在於確保執行緒安全性,而不是維持次序。

讓我們以一個實際生活的例子來說明。 想像一個網站上的密碼提交帖子。使用同步集合,多個用戶可以同時提交密碼。 每次“提交”動作如同一個執行緒,而同步集合則確保每次提交是執行緒安全的,並能被安全且有效地處理。

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>();
Imports System.Collections.Concurrent

Private recommendedBooks As New ConcurrentDictionary(Of 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);
}
Public Sub Insert(ByVal user As String, ByVal book As String)
	' Try to add the book to the user's recommendations
	recommendedBooks.TryAdd(user, book)
End Sub
$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);
}
Public Sub RemoveAt(ByVal user As String)
	' Attempt to remove the book for the specified user
	Dim removedBook As String = Nothing
	recommendedBooks.TryRemove(user, removedBook)
End Sub
$vbLabelText   $csharpLabel

TryRemove 方法將嘗試移除提供的鍵(在這裡是一個用戶)的值並將其放入 removedBook 變量中。

複製同步集合

現在,假設你想將同步集合複製到一個數組中。 同步集合提供了 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);
}
Public Sub CopyTo()
	' Create an array to hold the recommended books
	Dim bookArray(recommendedBooks.Count - 1) As String

	' Copy the values of the concurrent dictionary to the array
	recommendedBooks.Values.CopyTo(bookArray, 0)
End Sub
$vbLabelText   $csharpLabel

在這裡,CopyTo 方法將所有書本(值)從 recommendedBooks 同步字典中複製到 bookArray

執行緒安全的集合

C# 還提供 執行緒安全的集合,這些集合專為確保在多執行緒環境中安全地存取共享資源而設計。 這些集合,例如 ConcurrentBagConcurrentQueueConcurrentStack,提供執行緒安全的實現,使多個執行緒可以同時存取並修改集合而不會造成衝突或數據損壞。

它們通過內部處理同步來保證一致性和完整性,使其成為 C# 應用程式中無序集合足夠、且執行緒安全性至關重要的情境下的理想選擇。

Learn More About IronPDF is a popular C# library that allows you to 從 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");
    }
}
Imports IronPdf

Friend Class Program
	Shared Sub Main(ByVal args() As String)
		Dim renderer = New ChromePdfRenderer()

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

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

		' 3. Convert URL to PDF
		Dim url = "http://ironpdf.com" ' Specify the URL
		Dim pdfFromUrl = renderer.RenderUrlAsPdf(url)
		pdfFromUrl.SaveAs("URLToPDF.pdf")
	End Sub
End Class
$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
}
Imports IronPdf
Imports System.Collections.Concurrent
Imports System.Collections.Generic
Imports System.Threading.Tasks

' Create a concurrent dictionary to hold your processed data
Private processedData As New ConcurrentDictionary(Of Integer, String)()

' Define your data list (replace with your actual data source)
Private dataList As List(Of DataItem) = GetDataList()

' Process your data concurrently and store the results in the dictionary
Parallel.ForEach(dataList, Sub(dataItem)
	' Process each data item and add the result to the dictionary
	Dim processedResult As String = ProcessDataItem(dataItem)
	processedData.TryAdd(dataItem.Id, processedResult)
End Sub)

' Generate a PDF report with the processed data
Dim renderer = New ChromePdfRenderer()
Dim 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)
'INSTANT VB TODO TASK: Local functions are not converted by Instant VB:
'List(Of 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)
'INSTANT VB TODO TASK: Local functions are not converted by Instant VB:
'string ProcessDataItem(DataItem dataItem)
'{
'	' Simulating data processing with a delay
'	Task.Delay(100).Wait();
'	Return string.Format("Processed: {0}", dataItem.Name);
'}

' Method to build the HTML report using the processed data (replace with your actual reporting logic)
'INSTANT VB TODO TASK: Local functions are not converted by Instant VB:
'string BuildHtmlReport(ConcurrentDictionary(Of int, string) processedData)
'{
'	string html = "<h1>Processed Data Report</h1><ul>";
'	foreach (var kvp in processedData)
'	{
'		html += string.Format("<li>Item {0}: {1}</li>", kvp.Key, kvp.Value);
'	}
'	html += "</ul>";
'	Return html;
'}

' Placeholder class for your data item (replace with your actual data item class)
'INSTANT VB TODO TASK: Local functions are not converted by Instant VB:
'public class DataItem
'{
'	public int Id
'	{
'		get;
'		set;
'	}
'	public string Name
'	{
'		get;
'		set;
'	}
'	' Add other properties as needed
'}
$vbLabelText   $csharpLabel

以下是程式碼的輸出:

C# 同步列表(它對開發人員的運作原理)圖 1 - 輸出

結論

總之,理解和使用 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報告,使得更容易整合和分享來自多執行緒操作的結果。

Curtis Chau
技術作家

Curtis Chau 擁有卡爾頓大學計算機科學學士學位,專注於前端開發,擅長於 Node.js、TypeScript、JavaScript 和 React。Curtis 熱衷於創建直觀且美觀的用戶界面,喜歡使用現代框架並打造結構良好、視覺吸引人的手冊。

除了開發之外,Curtis 對物聯網 (IoT) 有著濃厚的興趣,探索將硬體和軟體結合的創新方式。在閒暇時間,他喜愛遊戲並構建 Discord 機器人,結合科技與創意的樂趣。