随着数据量的不断增长,高效地处理大量数据已成为开发者必须面对的挑战。C# 中的任务并行库(Task Parallel Library,简称 TPL)提供了简便且强大的方式来实现并行编程,充分利用多核处理器的优势,加速数据处理。本篇文章将详细介绍如何使用 TPL 处理大量数据,并提供完整的示例代码。
TPL 是 .NET Framework 提供的用于实现并行编程的库,位于 System.Threading.Tasks
命名空间下。它简化了多线程编程,帮助开发者更容易地创建、等待和管理任务。
Parallel
类提供了并行执行循环的功能,如 Parallel.For
和 Parallel.ForEach
,可用于并行处理集合中的数据。
假设我们有一个包含大量整数的列表,需要对每个整数进行计算处理。
下面是完整的代码示例:
C#using System.Collections.Generic;
namespace AppTPL
{
internal class Program
{
static void Main(string[] args)
{
List<int> numbers = GenerateLargeData(1000000);
ProcessData(numbers);
}
static List<int> GenerateLargeData(int count)
{
List<int> data = new List<int>(count);
for (int i = 0; i < count; i++)
{
data.Add(i);
}
return data;
}
static void ProcessData(List<int> data)
{
Parallel.ForEach(data, number =>
{
// 模拟计算密集型任务
double result = Math.Pow(number, 2);
// 处理结果(此处省略)
Console.WriteLine(result);
});
}
}
}
以上代码中,Parallel.ForEach
方法将列表中的数据分配到多个线程中并行处理,从而加速处理过程。
除了并行处理循环,TPL 还允许创建和管理自定义任务,可用于更复杂的并行操作。
假设我们需要从多个 URL 下载文件,我们可以使用 Task
来并行执行下载操作。
下面是完整的代码示例:
C#using System;
using System.Collections.Generic;
namespace AppTPL
{
internal class Program
{
static async Task Main(string[] args)
{
List<string> urls = new List<string>
{
"https://images.pexels.com/photos/16471876/pexels-photo-16471876.jpeg?cs=srgb&dl=pexels-helloaesthe-16471876.jpg&fm=jpg&_gl=1*1vqwmcp*_ga*OTYxNjI2MTc3LjE3Mjk0Nzc4NDM.*_ga_8JE65Q40S6*MTczNDIxNjIxMi4zLjEuMTczNDIxNjIxNS4wLjAuMA..",
"https://images.pexels.com/photos/18884059/pexels-photo-18884059.jpeg?cs=srgb&dl=pexels-aljona-ovtsinnikova-121486965-18884059.jpg&fm=jpg&_gl=1*1vqwmcp*_ga*OTYxNjI2MTc3LjE3Mjk0Nzc4NDM.*_ga_8JE65Q40S6*MTczNDIxNjIxMi4zLjEuMTczNDIxNjIxNS4wLjAuMA..",
};
await DownloadFilesAsync(urls);
}
static async Task DownloadFilesAsync(List<string> urls)
{
List<Task> downloadTasks = new List<Task>();
foreach (var url in urls)
{
downloadTasks.Add(Task.Run(async () =>
{
using HttpClient client = new HttpClient();
var data = await client.GetByteArrayAsync(url);
File.WriteAllBytes(new Random().Next(1, 1000000) + ".jpg", data);
// 保存数据(此处省略)
}));
}
await Task.WhenAll(downloadTasks);
}
}
}
在此示例中,我们为每个下载操作创建一个任务,并使用 Task.WhenAll
方法等待所有下载任务完成。
并行 LINQ(PLINQ)提供了并行化 LINQ 查询的能力,可以对数据集合进行并行查询和处理。
下面是完整的代码示例:
C#using System;
using System.Collections.Generic;
namespace AppTPL
{
internal class Program
{
static void Main(string[] args)
{
List<int> numbers = GenerateLargeData(1000);
ProcessDataWithPLINQ(numbers);
}
static List<int> GenerateLargeData(int count)
{
List<int> data = new List<int>(count);
for (int i = 0; i < count; i++)
{
data.Add(i);
}
return data;
}
static void ProcessDataWithPLINQ(List<int> data)
{
var results = data.AsParallel()
.Where(number => number % 2 == 0)
.Select(number => Math.Sqrt(number))
.ToList();
Console.WriteLine("Results: " + string.Join(", ", results));
}
}
}
使用 AsParallel()
方法将集合转换为并行查询,后续的查询操作将自动并行执行。
在并行处理中,需注意线程安全问题。如需要修改共享数据,应使用线程安全的数据结构或使用锁。
下面是完整的代码示例:
C#using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
namespace AppTPL
{
internal class Program
{
static List<int> GenerateLargeData(int count)
{
List<int> data = new List<int>(count);
for (int i = 0; i < count; i++)
{
data.Add(i);
}
return data;
}
static void Main(string[] args)
{
List<int> numbers = GenerateLargeData(1000000);
ProcessDataSafely(numbers);
}
static void ProcessDataSafely(List<int> data)
{
ConcurrentBag<double> results = new ConcurrentBag<double>();
Parallel.ForEach(data, number =>
{
double result = Math.Pow(number, 2);
results.Add(result);
});
// 结果已安全地添加到线程安全的集合中
}
}
}
ConcurrentBag
是一个线程安全的集合,允许多个线程同时添加和读取数据。
任务并行库(TPL)为 C# 开发者提供了强大的并行处理能力,能够有效地处理大量数据。通过 Parallel
类、Task
和 PLINQ,可以根据不同的需求选择合适的并行处理方式。在实际应用中,需要注意线程安全和资源管理,以确保程序的正确性和高效性。
本文作者:技术老小子
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!