异步读/写多个文件

时间:2016-07-14 13:18:23

标签: c# asp.net asynchronous io task-parallel-library

我们正在构建一个自定义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();
            }
        }
    } 

2 个答案:

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