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>();
Imports System.Collections.Concurrent
Private recommendedBooks As New ConcurrentDictionary(Of String, String)()
要將一本書新增到用戶的全部推薦收藏中,我們可以使用以下方法:
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
在這種情況下, ConcurrentDictionary 集合類別確保每次點擊(或"執行緒")都被單獨處理,因此不會出現兩個使用者推薦內容混淆的情況。它處理了所有線程安全問題,因此您無需擔心資料競爭和其他與多線程相關的並發問題。
實現線程安全作業
除了 TryAdd 之外,C# 中的並發集合還提供了各種其他線程安全操作,如 TryRemove 和 TryUpdate。 這些方法確保一次只能有一個執行緒執行操作。例如,如果我們想從上例中使用者的推薦清單中刪除一本書,我們可以使用以下方法:
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
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
在這裡,CopyTo 方法將 recommendedBooks 並發字典中的所有書籍(值)複製到 bookArray 中。
線程安全收集
C# 也提供 thread-safe 集合,其目的是確保在多執行緒環境中安全存取共用資源。 這些集合,例如 ConcurrentBag、ConcurrentQueue 和 ConcurrentStack,提供了線程安全的實現,其中多個線程可以並發存取和修改集合,而不會造成衝突或資料損壞。
這些工具透過內部處理同步化來保證一致性和完整性,因此非常適用於無序集合已足夠的情況,而線程安全在您的 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");
}
}
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
儘管 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
'}
以下是程式碼的輸出:

結論
總而言之,瞭解並運用 C# 並發集合(例如並發清單),可以大幅提升您處理多執行緒情境的能力,並確保應用程式中的線程安全。 使用並發集合,您可以有效地管理共用資源,防止資料競賽和線程間的碰撞。
整合 IronPDF 之類的外部函式庫,可以藉由產生視覺上吸引人的 PDF 報告或文件,進一步強化並發集合的功能。 IronPDF 提供HTML 轉 PDF 轉換庫的免費試用版,讓您可以探索其功能,許可選項從 $999 起。
常見問題解答
什麼是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報告,使得更容易整合和分享來自多執行緒操作的結果。



