gpt4 book ai didi

c# - 如何使用 TPL 并行化文件写入?

转载 作者:行者123 更新时间:2023-11-30 13:55:57 24 4
gpt4 key购买 nike

我正在尝试将字符串列表保存到多个文件中,每个字符串保存在不同的文件中,并同时进行。我这样做:

public async Task SaveToFilesAsync(string path, List<string> list, CancellationToken ct)
{
int count = 0;
foreach (var str in list)
{
string fullPath = path + @"\" + count.ToString() + "_element.txt";
using (var sw = File.CreateText(fullPath))
{
await sw.WriteLineAsync(str);
}
count++;

NLog.Trace("Saved in thread: {0} to {1}",
Environment.CurrentManagedThreadId,
fullPath);

if (ct.IsCancellationRequested)
ct.ThrowIfCancellationRequested();
}
}

然后这样调用它:

try
{
var savingToFilesTask = SaveToFilesAsync(@"D:\Test", myListOfString, ct);
}
catch(OperationCanceledException)
{
NLog.Info("Operation has been cancelled by user.");
}

但是在日志文件中我可以清楚地看到保存总是发生在同一个线程 id 中,所以没有并行处理?我究竟做错了什么?如何解决?我的目标是使用所有计算机内核尽可能快地进行所有保存。

最佳答案

本质上,您的问题是 foreach 是同步的。它使用同步的 IEnumerable

要解决这个问题,首先将循环体封装到一个异步函数中。

public async Task WriteToFile(
string path,
string str,
int count)
{
var fullPath = string.Format("{0}\\{1}_element.txt", path, count);
using (var sw = File.CreateText(fullPath))
{
await sw.WriteLineAsync(str);
}

NLog.Trace("Saved in TaskID: {0} to \"{1}\"",
Task.CurrentId,
fullPath);
}

然后,不是同步循环,而是将字符串序列转换到执行封装循环体的一系列任务。这本身不是异步操作,但投影不会阻塞,即没有 await

然后等待它们按照任务计划程序定义的顺序完成所有任务。

public async Task SaveToFilesAsync(
string path,
IEnumerable<string> list,
CancellationToken ct)
{
await Task.WhenAll(list.Select((str, count) => WriteToFile(path, str, count));
}

没有什么可以取消的,所以没有必要向下传递取消 token 。

我使用了 Select 的索引重载来提供 count 值。

我已经更改了您的日志记录代码以使用当前的任务 ID,这样可以避免在安排方面造成任何困惑。

关于c# - 如何使用 TPL 并行化文件写入?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31020747/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com