.NET 幫助

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

發佈 2023年6月6日
分享:

如果您曾經遇到多個執行緒爭奪對共享資源的訪問權,您就知道執行緒安全實現不是鬧著玩的。不過,請不用擔心! C# 用同步集合來解決問題 - 一個功能強大的執行緒安全泛型集合類別套件,以優雅的方式確保執行緒的安全性。

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

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

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

在C#中,命名空間 System.Collections.Concurrent 包含多種並發集合類,如 ConcurrentDictionaryConcurrentQueueConcurrentStackConcurrentBag。這些無序集合類提供了它們非並發對應版的線程安全版本。並發集合異於其他集合的特點在於它們是無序的並發集合,這意味著元素沒有特定的順序。例如,在使用並發列表時,你無法確定物件插入的確切位置。重點在於確保線程安全,而不是維持順序。

讓我們舉個現實生活中的例子。想像在一個網站上提交密碼的帖子。利用並發集合,多個用戶可以同時提交他們的密碼。每次“提交”行動就像一個線程,並發集合確保每次提交都是線程安全的,並且被安全有效地處理。

ConcurrentDictionary 一個真實世界的例子

現在,讓我們用一個真實生活中的例子來探索 ConcurrentDictionary 集合類別。想像一個有推薦功能的在線書店。每個用戶的點擊會將一本書添加到他們的個人推薦列表中,該列表由一個字典表示。由於多個用戶同時瀏覽和點擊書籍,我們有多個線程同時訪問該字典。

在 C# 中 ConcurrentDictionary 會看起來像這樣:

ConcurrentDictionary recommendedBooks = new ConcurrentDictionary();
ConcurrentDictionary recommendedBooks = new ConcurrentDictionary();
Dim recommendedBooks As New ConcurrentDictionary()
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。這些方法確保一次只能有一個執行緒執行操作。因此,例如,如果我們想要從上一個例子中的使用者推薦中刪除一本書,我們可以使用 RemoveAt 方法。

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 processedData = new ConcurrentDictionary();

// Define your data list (replace with your actual data source)
List 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 GetDataList()
{
    List dataList = new List()
    {
        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 processedData)
{
    string html = "Processed Data Report";
    foreach (var kvp in processedData)
    {
        html += $"Item {kvp.Key}: {kvp.Value}";
    }
    html += "";
    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 processedData = new ConcurrentDictionary();

// Define your data list (replace with your actual data source)
List 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 GetDataList()
{
    List dataList = new List()
    {
        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 processedData)
{
    string html = "Processed Data Report";
    foreach (var kvp in processedData)
    {
        html += $"Item {kvp.Key}: {kvp.Value}";
    }
    html += "";
    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()

' Define your data list (replace with your actual data source)
Private dataList As List = 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 GetDataList()
'{
'	List dataList = New List() { 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 processedData)
'{
'	string html = "Processed Data Report";
'	foreach (var kvp in processedData)
'	{
'		html += string.Format("Item {0}: {1}", kvp.Key, kvp.Value);
'	}
'	html += "";
'	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 提供了 免費試用,讓您探索其功能,許可選項從 $749 開始。

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

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

免費 NuGet 下載 總下載次數: 10,993,239 查看許可證 >