【发布时间】:2017-08-30 20:11:01
【问题描述】:
我从Writing Large, Responsive .NET Framework Apps 发现了下面的代码。
下面的代码使用StringBuilder 创建了一个类似SomeType<T1, T2, T3> 的字符串,并演示了缓存StringBuilder 以提高性能。
public void Test3()
{
Console.WriteLine(GenerateFullTypeName("SomeType", 3));
}
// Constructs a name like "SomeType<T1, T2, T3>"
public string GenerateFullTypeName(string name, int arity)
{
//StringBuilder sb = new StringBuilder();
StringBuilder sb = AcquireBuilder();
sb.Append(name);
if (arity != 0)
{
sb.Append("<");
for (int i = 1; i < arity; i++)
{
sb.Append("T"); sb.Append(i.ToString()); sb.Append(", ");
}
sb.Append("T"); sb.Append(arity.ToString()); sb.Append(">");
}
//return sb.ToString();
/* Use sb as before */
return GetStringAndReleaseBuilder(sb);
}
[ThreadStatic]
private static StringBuilder cachedStringBuilder;
private static StringBuilder AcquireBuilder()
{
StringBuilder result = cachedStringBuilder;
if (result == null)
{
return new StringBuilder();
}
result.Clear();
cachedStringBuilder = null;
return result;
}
private static string GetStringAndReleaseBuilder(StringBuilder sb)
{
string result = sb.ToString();
cachedStringBuilder = sb;
return result;
}
但是,下面的两个修改方法在缓存StringBuilder方面更好是正确的吗?只有 AcquireBuilder 需要知道如何缓存它。
private static StringBuilder AcquireBuilder()
{
StringBuilder result = cachedStringBuilder;
if (result == null)
{
//unlike the method above, assign it to the cache
cachedStringBuilder = result = new StringBuilder();
return result;
}
result.Clear();
//no need to null it
// cachedStringBuilder = null;
return result;
}
private static string GetStringAndReleaseBuilder(StringBuilder sb)
{
string result = sb.ToString();
//other method does not to assign it again.
//cachedStringBuilder = sb;
return result;
}
另外一个问题是原来的方法不是线程安全的,为什么demo中使用了ThreadStatic?
【问题讨论】:
-
这是
AcquireBuilder的更好实现:ObjectPool<StringBuilder>.Get。这是 ASP.NET 本身使用的;我不知道为什么作者觉得有必要想出一些原创的东西。 -
这已经是built into the framework。看起来很相似。请确保您需要它,请记住,没有过期策略的缓存是内存泄漏。
标签: c#