.NET 幫助

C# 並發列表(開發人員如何使用)

發佈 2023年6月6日
分享:

如果您曾經遇到多個執行緒爭奪對共享資源的訪問權,您就會知道執行緒安全實現不是遊戲。 不過,別擔心! C# 提供並行集合——一套強大的執行緒安全泛型集合類別,以優雅的方式確保執行緒安全性。

C# 中的執行緒安全與並發集合

讓我們先想像一個沒有紅綠燈的繁忙城市十字路口。 你可以想象混亂! 這類似於多個執行緒同時訪問共享資源而沒有適當機制時的情況。 幸運的是,在 C# 中,我們有用於線程的交通號誌——這些被稱為並發集合。 它們是集合類別,允許一次只有一個執行緒訪問資源。在處理多個執行緒時,這種執行緒安全性至關重要。

探索 C# 中的並發執行緒安全集合

在 C# 中,命名空間 System.Collections.Concurrent 具有多種類型的並發集合類別,如 ConcurrentDictionaryConcurrentQueueConcurrentStackConcurrentBag。 這些無序集合類提供其非並發對應類的執行緒安全版本。 並發集合的獨特之處在於它們是無序的並發集合,這意味著元素沒有特定的順序。 例如,對於併發列表,您無法準確知道一個項目被插入的位置。 重點在於確保線程安全,而不是維持順序。

讓我們以一個實際生活範例來說明。 想像一下網站上的密碼提交帖子。使用並發集合,多個用戶可以同時提交他們的密碼。 每個「提交」操作就像一個線程,而並發集合可確保每次提交都是線程安全的,處理安全且有效。

ConcurrentDictionary:一個現實世界的範例

現在,讓我們透過一個實際生活中的例子來探索 ConcurrentDictionary 集合類別。 想像一個具有推薦功能的線上書店。 每位使用者的點擊都會將一本書添加到他們的個人推薦清單中,以字典表示。 當多個使用者同時瀏覽和點擊書籍時,我們有多個線程同時存取該字典。

C# 中的 ConcurrentDictionary 看起來像這樣:

ConcurrentDictionary<string, string> recommendedBooks = new ConcurrentDictionary<string, string>();
ConcurrentDictionary<string, string> recommendedBooks = new ConcurrentDictionary<string, string>();
Dim recommendedBooks As New ConcurrentDictionary(Of String, String)()
VB   C#

要將書添加到用戶的所有推薦收藏中,我們可以使用 Insert 方法:

public void Insert(string user, string book)
{
    recommendedBooks.TryAdd(user, book);
}
public void Insert(string user, string book)
{
    recommendedBooks.TryAdd(user, book);
}
Public Sub Insert(ByVal user As String, ByVal book As String)
	recommendedBooks.TryAdd(user, book)
End Sub
VB   C#

在此情境中,ConcurrentDictionary 集合類別 確保每次點擊(或 '執行緒')每個用戶都會單獨處理,因此不會混淆兩個用戶的推薦。 它處理所有的線程安全性,所以您不必擔心與多線程相關的數據競爭和其他並發問題。

實作執行緒安全操作

除了 TryAdd 之外,C# 中的並發集合還提供多種其他執行緒安全的操作,如 TryRemoveTryUpdate。 這些方法確保一次只有一個執行緒可以執行操作。因此,例如,如果我們想從上一個例子中移除用戶的推薦書籍,我們可以使用 TryRemove 方法:

public void RemoveAt(string user)
{
    string removedBook;
    recommendedBooks.TryRemove(user, out removedBook);
}
public void RemoveAt(string user)
{
    string removedBook;
    recommendedBooks.TryRemove(user, out removedBook);
}
Public Sub RemoveAt(ByVal user As String)
	Dim removedBook As String = Nothing
	recommendedBooks.TryRemove(user, removedBook)
End Sub
VB   C#

TryRemove 方法將嘗試移除所提供鍵的值(在這種情況下,用戶)並將其放入 removedBook 變數中。

複製並發集合

現在,假設您想要將並發集合複製到陣列中。 並發集合提供了適用於此目的的 CopyTo 方法:

public void CopyTo()
{
    string[] bookArray = new string[recommendedBooks.Count];
    recommendedBooks.Values.CopyTo(bookArray, 0);
}
public void CopyTo()
{
    string[] bookArray = new string[recommendedBooks.Count];
    recommendedBooks.Values.CopyTo(bookArray, 0);
}
Public Sub CopyTo()
	Dim bookArray(recommendedBooks.Count - 1) As String
	recommendedBooks.Values.CopyTo(bookArray, 0)
End Sub
VB   C#

以下是 CopyTo 方法的全部書籍複製(值)從 recommendedBooks 並行字典移到 bookArray

線程安全集合

C# 也提供執行緒安全集合,旨在確保在多執行緒環境中安全訪問共享資源。 這些集合,例如 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");
    }
}
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
VB   C#

雖然乍看之下與並行列表沒有直接關係,但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) =>
{
    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) =>
{
    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)
	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
'}
VB   C#

以下是程式碼的輸出:

C# 並行列表(對開發人員的工作方式)圖 1 - 輸出

結論

總結來說,理解和利用 C# 並發集合,例如並發列表,可以大大提高你處理多線程場景的能力,並確保你的應用程式的線程安全性。 使用並行集合,您可以有效管理共享資源,預防線程之間的數據競賽和衝突。

整合像 IronPDF 這樣的外部庫,可以通過啟用生成視覺上吸引人的 PDF 報告或文件來進一步增強並發集合的功能。 IronPDF 提供一個其 HTML 到 PDF 轉換庫的免費試用版,讓您探索其功能,許可選項從 $749 開始。

< 上一頁
什麼是Visual Studio(其對開發人員的作用)
下一個 >
適用 Windows 的 Vim (開發人員的操作方式)

準備開始了嗎? 版本: 2024.12 剛剛發布

免費 NuGet 下載 總下載次數: 11,622,374 查看許可證 >