我有一个Windows表单应用程序,目前执行以下操作:
1)指向一个目录并对其中的所有xml文件执行2(通常最多25个文件,范围从10mb到!5gb! - 不常见但可能)
2)xml读/写改变一些现有的xml属性(目前我使用一个后台工作者)
3)将更改的xml属性直接写入不同目录中的NEW文件
小应用程序工作正常,但完成需要太长时间(约20分钟,具体取决于净gb大小) 我随便尝试的是在Parallel.ForEach()中启动主要的rw方法,但它不会出乎意料地阻止自己退出
我的想法是通过在所有~25个文件上同时启动它来并行化读/写过程这是明智的吗?我怎么能这样做(TPL?)而不是把自己锁在外面?
PS:我有一台功能强大的台式机,拥有1TB三星专业版,16GB内存和英特尔酷睿i7答案 0 :(得分:1)
您可以使用此方法的ThreadPool
您可以拥有一个大小为20个文件的池 因为你有核心i7,你应该使用 TaskFactory.StartNew 在这种情况下,您应该在XMLProcessor之类的示例类中封装用于处理文件的代码 然后使用TaskFactory.StartNew,您可以使用多线程进行xml processsing
答案 1 :(得分:0)
这听起来像是通过PLINQ +异步lambdas进行数据并行的工作。
我最近需要处理来自zip存档的数据,该存档本身包含5,200个zip存档,然后每个存档包含一个或多个XML或CSV格式的数据文件。在解压缩和读入内存时总共有40-60 GB的数据。
算法浏览这些数据,根据它与提供的谓词一起找到的内容做出决策,最后将选择内容写入1.0-1.5 GB文件。使用具有32个处理器的异步PLINQ模式,每个输出文件的平均运行时间为4.23分钟。
在使用async PLINQ实现简单的解决方案之后,我花了一些时间来尝试通过深入研究TPL和TPL Dataflow库来改善运行时间。最后,尝试击败async PLINQ被证明是一种有趣但最终无用的运动来满足我的需求。来自更“优化”的解决方案的性能利润不值得增加复杂性。
以下是异步PLINQ模式的示例。初始集合是一个文件路径数组。
在第一步中,将每个文件路径异步读入内存并进行解析,将文件名缓存为根级属性,然后流式传输到下一个函数。
在最后一步中,每个XElement
都异步写入新文件。
我建议您使用读取文件的lambda。在我的例子中,我发现通过异步lambda读取在解压缩内存中的文件时给了我更好的吞吐量。
但是,对于简单的XML文档,最好用方法调用XElement.Load(string file)
替换第一个异步lambda,然后根据需要读取PLINQ。
using System.IO;
using System.Linq;
using System.Xml.Linq;
namespace AsyncPlinqExample
{
public class Program
{
public static void Main(string[] args)
{
// Limit parallelism here if needed
int degreeOfParallelism = Environment.ProcessorCount;
string resultDirectory = "[result directory path here]";
string[] files = Directory.GetFiles("[directory with files here]");
files.AsParallel()
.WithDegreeOfParallelism(degreeOfParallelism)
.Select(
async x =>
{
using (StreamReader reader = new StreamReader(x))
{
XElement root = XElement.Parse(await reader.ReadToEndAsync());
root.SetAttributeValue("filePath", Path.GetFileName(x));
return root;
}
})
.Select(x => x.Result)
.Select(
x =>
{
// Perform other manipulations here
return x;
})
.Select(
async x =>
{
string resultPath =
Path.Combine(
resultDirectory,
(string) x.Attribute("fileName"));
await Console.Out.WriteLineAsync($"{DateTime.Now}: Starting {(string) x.Attribute("fileName")}.");
using (StreamWriter writer = new StreamWriter(resultPath))
{
await writer.WriteAsync(x.ToString());
}
await Console.Out.WriteLineAsync($"{DateTime.Now}: Comleted {(string)x.Attribute("fileName")}.");
});
}
}
}