.NET 帮助

C# 并发列表(对开发人员的工作原理)

发布 2023年六月6日
分享:

如果您曾有过多个线程争相访问共享资源的经历,您就会知道线程安全的实现并不是一场游戏。 不过不用担心! C# 为您提供了并发集合--一套功能强大的线程安全通用集合类,确保线程安全的同时又不失风格和优雅。

C# 中的线程安全和并发集合》(Thread Safety and Concurrent Collections in 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 "方法复制了所有图书(价值观)推荐书籍 "并发字典中的 "bookArray"。

线程安全集合

C# 还提供了线程安全集合例如,.NET、Java、Python 或 Node js,这些工具旨在确保在多线程环境中安全访问共享资源。 这些集合(如 "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
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(它对开发人员如何工作)
下一步 >
Vim for Windows(开发人员如何使用)

准备开始了吗? 版本: 2024.12 刚刚发布

免费NuGet下载 总下载量: 11,781,565 查看许可证 >