【发布时间】:2021-02-05 04:14:04
【问题描述】:
对于我的控制台应用程序,我实现了一个简单的文件记录器。记录器使用StringBuilder 来保持追加日志条目并将LogText 数据写入最后的LogFile。这导致只有一个文件 I/O 操作。应用程序的执行必须非常快,因此,我已经实现了Parallel.ForEach 以及async-await,并尽可能减少了 I/O 操作。
问题是Logger 不是线程安全的。使用lock 或Monitor 在Parallel.ForEach 循环内同步共享资源logger 会降低性能。有没有什么对执行速度影响不大的共享资源同步的最佳方式?
我愿意接受其他方法或建议。
Logger.cs
public class Logger
{
private readonly string LogFile;
private readonly StringBuilder LogText;
public Logger(string logFile)
{
LogFile = logFile;
LogText = new StringBuilder();
}
public void Write(string message)
{
LogText.AppendLine(message);
}
public void WriteToFile()
{
File.AppendAllText(LogFile, LogText.ToString());
}
}
程序.cs
public class Program
{
public static void Main(string[] args)
{
string logFile = args[0];
string workingDirectory = args[1];
Logger logger = new Logger(logFile);
logger.Write($"INFO | Execution Started");
try
{
List<string> files = Directory.EnumerateFiles(workingDirectory, "*", SearchOption.AllDirectories).ToList();
Parallel.ForEach(files, async file =>
{
List<string> results = await PerformCPUBoundComputationAsync();
foreach(string result in results)
{
logger.Write($"INFO | Item: {result}");
}
string response = await MakePostRequestAsync(results);
logger.Write($"INFO | Response: {response}");
});
}
catch (Exception ex)
{
logger.Write($"ERROR | {ex.Message}");
}
finally
{
logger.Write($"INFO | Execution Ended");
logger.WriteToFile();
}
}
}
【问题讨论】:
-
“我又做了一个东西,好吗?”问题应该去codereview。 lock-free同步还有几十个问题,请先研究一下。
-
Hrm,为什么不直接使用一个已经解决了所有这些问题的日志框架,并且您将拥有更多呢?但是这段代码有一些非常可疑的部分,
Parallel.ForEach(files, async file您正在使用 Parallel.ForEach 来启动一堆异步 void,PerformCPUBoundComputation是异步的,看起来有点奇怪。显然这根本不是线程安全的,但你知道 -
日志是否需要按运行时间顺序排列?日志有点乱有关系吗?
-
是
MakePostRequestIO 绑定工作吗?你为什么不等这个? -
Api 调用意味着 IO 绑定,即它通过您的网卡输出
标签: c# .net multithreading concurrency parallel-processing