我们正在构建一个自定义CMS,我们必须通过我的管理面板一次性覆盖服务器上多个HTML文件(大约1000个)的内容。我是异步和并行编程的新手所以在一些R& D之后我决定使用并行编程(TPL)解决我的问题,下面是我用来用一些文本覆盖文件的示例代码。
现在的问题是我必须并行读取多个文件,在我的例子中我使用的是一个简单的变量字符串text ="在文件" + index.ToString(),但实际上每个被覆盖的文件将被静态模板(对于每个页面)和一些来自数据库的动态值(对于CMS元素)替换。我不明白如何对多个文件并行执行多次读/写操作:
static async void ProcessWriteMultAsync()
{
string folder = @"E:\test\";
string[] items = { "Site1", "Site2", "Site3", "Site4", "Site5", "Site6", "Site7", "Site8", "Site9", "Site10", "Site11", "Site12", "Site13", "Site14",
"Site15","Site16","Site17","Site18","Site19","Site20",};
List<Task> tasks = new List<Task>();
List<FileStream> sourceStreams = new List<FileStream>();
try
{
for (int index = 0; index < items.Length; index++)
{
string text = "In file " + index.ToString();
string filePath = folder + items[index] + "\\ProcurementTemplate.html";
byte[] encodedText = Encoding.Unicode.GetBytes(text);
FileStream sourceStream = new FileStream(filePath,
FileMode.Create, FileAccess.Write, FileShare.None,
bufferSize: 4096, useAsync: true);
Task theTask = sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
sourceStreams.Add(sourceStream);
tasks.Add(theTask);
}
await Task.WhenAll(tasks);
}
finally
{
foreach (FileStream sourceStream in sourceStreams)
{
sourceStream.Close();
}
}
}
答案 0 :(得分:2)
首先,拉出逻辑将文件写入方法:
async Task Write(string text, string filePath) {
byte[] encodedText = Encoding.Unicode.GetBytes(text);
using (FileStream sourceStream = new FileStream(filePath)) {
await sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
}
}
然后使用Stephen Toubs ForEachAsync
处理所有项目。您需要通过实验确定正确的并行度。它肯定不会是1000,因为它现在在您的代码中。正确的DOP取决于IO系统以及OS缓冲的数据量。
items.ForEachAsync(async (item) => await Write(item, GetPath(...)), dop: 8);
旧代码基本上有效,但它的级别和冗长都很低。
答案 1 :(得分:0)
您可以创建一个任务数组 - 每个文件一个 - 然后使用Task.WaitAll
全部运行:
public async Task DoWorkAsync(string text, string file)
{
using(FileStream sourceStream = new FileStream(file, FileMode.Create, FileAccess.Write))
{
byte[] encodedText = Encoding.Unicode.GetBytes(text);
await sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
}
}
IEnumerable<string> fileNames = new string[] { "file1.txt", "file2.txt" };
Task[] writingTasks = fileNames
.Select(fileName => DoWorkAsync("some text", fileName))
.ToArray();
await Task.WhenAll(writingTasks);