2016-07-14 105 views
1

我们正在构建一个定制的CMS,我们必须一次性通过我的管理面板覆盖服务器上的多个HTML文件(大约1000个)的内容。我是新来的异步和并行编程所以,在一些R & D我决定使用并行编程(TPL)来解决我的问题,下面是我用来用一些文本覆盖文件的示例代码。异步读取/写入多个文件

现在的问题是我必须同时读取多个文件,在我的例子中我使用了一个简单的变量字符串text =“In file”+ 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(); 
      } 
     } 
    } 

回答

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); 

旧的代码基本上工作,但它是相当低级别和详细。

+0

感谢您寻找到我的问题,只是为了你的信息我的服务器是一款16核的机器。你的观点是有效的,我的代码现在不是1000。另外你的意思是“旧的代码基本上可以工作,但它是相当低级和冗长的”,这意味着我的代码或其他东西。我怎样才能同时读/写,因为我必须加载模板文件并命中数据库1000次以加载其中的值。 – ChupChapCharli

+0

是的,旧的意味着你的。我不明白你评论中的问题。我的答案演示了如何以异步方式同时做某件事。这对你没有帮助吗? – usr

+0

我的问题是,写入方法中的文本参数将包含来自数据库的一些值,所以如果我有1000个文件,那么这意味着我必须调用数据库1000次。所以有可能异步实现这一点,因为看起来我必须逐个为每个文件调用Write函数。 – ChupChapCharli

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); 
+0

这将启动N个并发任务。当物品编号在千位时,这不是运行IO的正确方法。 – usr

+0

@waldemar:感谢您的回复,但是如何从数据库中读取“某些文本”,并且每个文件都不同。 – ChupChapCharli