到目前为止,我一直在C#库中开发static class
,所有方法显然都是静态的。传入任何被操纵的数据,因此这是线程安全的。但是,我正在实现一个功能,需要Dictionary
来计算某些字符串ID,这些ID将针对每个线程生成不同的内容。显然使用类似下面的内容将不是线程安全的,因为多个线程将使用相同的Dictionary
并使其状态陷入困境:
private static readonly Dictionary<string, uint> MyTallies = new Dictionary<string, uint>();
那么使这个线程安全的最佳选择是什么?我看到它的方式,有3个(有点坏)选项:
Dictionary
。表现很受欢迎。lock
在代码周围添加Dictionary
,并在锁定结束时清除Dictionary
。表现很好。Dictionary
传递给需要它的每个方法。然而,这会导致传递Dictionary
仅用于大多数时间不会使用的可选功能,因此调用代码必须要做的事情似乎很奇怪。此外,性能受到影响,因为调用代码每次都必须创建Dictionary
实例。那么这里我最好的选择是什么,还是有其他更好的选择我还没有想过?
编辑:一个简单的用例:
internal static class HtmlFormatter {
private static readonly Dictionary<string, uint> MyTallies = new Dictionary<string, uint>();
internal static string RenderHtml(string markdown) {
string outputHtml = "";
// (process markdown and render to HTML)
// (found a heading that requires a unique ID)
var id = generatedId;
string unique = "";
if (MyTallies.ContainsKey(id)) {
// Already exists; suffix "-x" where x is count of duplicate IDs
unique = "-" + ++MyTallies[id];
}
else {
MyTallies[id] = 0;
}
id += unique;
// (append id string to HTML output and continue processing)
return outputHtml;
}
}
答案 0 :(得分:0)
锁定对词典的访问权限。这样,方法不再是多线程的 - 只有一个方法将在方法中。查找锁定语句。
如果你更喜欢,请使用手动锁定 - 如果大多数访问权限是只读的,则多个读取器单个写入器可以提高性能。它允许多个读卡器锁,但一次只允许一个写入器。
3根本不是解决方案 - 因为字典不是线程安全的。除非您每次都使用ConcurrentDictionary或制作副本。
1不是解决方案,因为它是一种架构变化。它可能有用 - 但是为什么它首先是静态的?有一个原因,你要求我们在没有适当知识的情况下提供建议。
答案 1 :(得分:0)
感觉就像您预先优化一样,冒着编写过于复杂的代码的风险。我建议您编写最简单,最可靠的代码,直到您准确测试性能瓶颈为止。
除非你真的需要,否则通常最好避免在线程之间共享对象或状态。
使类非静态;每个线程都必须创建一个新实例, 并且可以为每个线程创建一个新的Dictionary。表现受到欢迎。
这是我推荐的方式。字典的一些额外字节可以忽略不计,甚至可以更快使用,因为每个字典中的项目数量会更少。
将Dictionary传递给需要它的每个方法。然而 这导致一个Dictionary只是为了一个可选的传递 大部分时间都不会使用的功能,所以看起来像是一个 调用代码必须要做的奇怪的事情。性能也受到了影响 因为调用代码每次都必须创建Dictionary实例。
我不能在不查看您的代码的情况下判断,但感觉您的代码执行得太多了。如果您考虑传入可能未使用的变量,那么您可能需要将代码分解为更小的组件。 (见Single Responsibility Principle)
如果事实结束时你确实需要在线程之间共享对象,那么有几个helpful patterns和类可以使用ConcurrentDictionary。 (感谢Eldar Dordzhiev)