C# 多线程 09-使用异步 I/O 01-异步地使用文件
🏷️ 《C# 多线程》
示例代码
csharp
/// <summary>
/// 异步地使用文件
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
var t = ProcessAsynchronousIO();
t.GetAwaiter().GetResult();
Console.ReadLine();
}
const int BUFFER_SIZE = 4096;
static async Task ProcessAsynchronousIO()
{
// 使用 FileStream 创建文件
using (var stream = new FileStream("test1.txt", FileMode.Create, FileAccess.ReadWrite, FileShare.None, BUFFER_SIZE))
{
Console.WriteLine($"1. Uses I/O Threads: {stream.IsAsync}");
byte[] buffer = Encoding.UTF8.GetBytes(CreateFileContent());
// 将异步编程模型 API 转换成任务
var writeTask = Task.Factory.FromAsync(stream.BeginWrite, stream.EndWrite, buffer, 0, buffer.Length, null);
await writeTask;
}
// 使用 FileStream 创建文件(提供了 FileOptions.Asynchronous 参数)
// 只有提供了提供了 FileOptions.Asynchronous 选项,才能对 FileStream 类使用异步 IO
using (var stream = new FileStream("test2.txt", FileMode.Create, FileAccess.ReadWrite, FileShare.None, BUFFER_SIZE, FileOptions.Asynchronous))
{
Console.WriteLine($"2. Uses I/O Threads: {stream.IsAsync}");
byte[] buffer = Encoding.UTF8.GetBytes(CreateFileContent());
// 将异步编程模型 API 转换成任务
var writeTask = Task.Factory.FromAsync(stream.BeginWrite, stream.EndWrite, buffer, 0, buffer.Length, null);
await writeTask;
}
// 使用 File.Create(提供了 FileOptions.Asynchronous 参数)和 StreamWriter 创建和写入文件
using (var stream = File.Create("test3.txt", BUFFER_SIZE, FileOptions.Asynchronous))
using (var sw = new StreamWriter(stream))
{
Console.WriteLine($"3. Uses I/O Threads: {stream.IsAsync}");
// 异步写入流
await sw.WriteAsync(CreateFileContent());
}
// 仅使用 StreamWriter 创建文件
using (var sw = new StreamWriter("test4.txt", true))
{
Console.WriteLine($"4. Uses I/O Threads: {((FileStream)sw.BaseStream).IsAsync}");
// 异步写入流(因为没有提供 FileOptions.Asynchronous 参数,Stream 其实并没有使用异步 I/O)
await sw.WriteAsync(CreateFileContent());
}
Console.WriteLine("Starting parsing files in parallel");
var readTasks = new Task<long>[4];
for (int i = 0; i < 4; i++)
{
string fileName = $"test{i + 1}.txt";
// 异步读取文件并 Sum
readTasks[i] = SumFileContent(fileName);
}
// 等待所有异步 Task 完成,并获取返回值数组
long[] sums = await Task.WhenAll(readTasks);
Console.WriteLine($"Sum is all files: {sums.Sum()}");
Console.WriteLine("Deleting files");
Task[] deleteTasks = new Task[4];
for (int i = 0; i < 4; i++)
{
string filename = $"test{i + 1}.txt";
// 异步删除文件
deleteTasks[i] = SimulateAsynchronousDelete(filename);
}
// 等待所有异步删除操作结束
await Task.WhenAll(deleteTasks);
Console.WriteLine("Deleting complete.");
}
/// <summary>
/// 异步删除文件
/// </summary>
/// <param name="filename"></param>
/// <returns></returns>
static Task SimulateAsynchronousDelete(string filename)
{
// 使用 Task.Run 模拟异步删除
return Task.Run(() => File.Delete(filename));
}
/// <summary>
/// 异步统计文件中随机数的合计值
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
static async Task<long> SumFileContent(string fileName)
{
// 使用 FileStream 和 StreamReader 异步读取文件
using (var stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.None, BUFFER_SIZE, FileOptions.Asynchronous))
using (var sr = new StreamReader(stream))
{
long sum = 0;
while (sr.Peek() > -1)
{
string line = await sr.ReadLineAsync();
sum += long.Parse(line);
}
return sum;
}
}
/// <summary>
/// 创建随机的文件内容
/// </summary>
/// <returns></returns>
static string CreateFileContent()
{
var sb = new StringBuilder();
for (int i = 0; i < 100000; i++)
{
sb.Append($"{ new Random(DateTime.Now.Millisecond).Next(0, 99999)}");
sb.AppendLine();
}
return sb.ToString();
}
运行结果
txt
1. Uses I/O Threads: False
2. Uses I/O Threads: True
3. Uses I/O Threads: True
4. Uses I/O Threads: False
Starting parsing files in parallel
Sum is all files: 19850361639
Deleting files
Deleting complete.