跳至页脚内容
.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 对物联网 (IoT) 有浓厚的兴趣,探索将硬件和软件集成的新方法。在空闲时间,他喜欢玩游戏和构建 Discord 机器人,将他对技术的热爱与创造力相结合。