StringBuilder with Caching, ThreadStatic

时间:2017-08-30 20:11:02

标签: c#

I came across the code below from Writing Large, Responsive .NET Framework Apps.

The code below creates a string like HTTP/1.1 200 OK Server: openresty/1.9.7.5 Date: Sun, 03 Sep 2017 13:02:55 GMT Content-Type: application/json; charset=utf-8 Transfer-Encoding: chunked Connection: keep-alive X-Frame-Options: SAMEORIGIN X-XSS-Protection: 1; mode=block X-Content-Type-Options: nosniff Access-Control-Allow-Origin: http://localhost:3000 Access-Control-Expose-Headers: Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS Access-Control-Allow-Headers: *,x-requested-with,Content-Type,If-Modified-Since,If-None-Match,latest_time Access-Control-Max-Age: 1728000 ETag: "eef3e52bc505031d93da42098f32cc60" Cache-Control: max-age=0, private, must-revalidate X-Request-Id: eb5c7353-0b4b-43c8-b2ff-4763d56d9ec9 X-Runtime: 0.015680 Access-Control-Allow-Credentials: true Vary: Origin using select number, max(case when category = 'A' then numberincategory end) as a, max(case when category = 'B' then numberincategory end) as b, max(case when category = 'C' then numberincategory end) as c from t group by number; , and demonstrating caching var table = document.getElementById('#my_table'); table.find('th').each(function(index) { var header_width = this.width(); table.find('tr').each(function() { $(this).find('td:nth-child('+index+')').width(header_width); }); }); to improve performance.

SomeType<T1, T2, T3>

However, is it correct that the two modified methods below are better in terms of caching StringBuilder?? Only AcquireBuilder needs to know how to cache it.

StringBuilder

Another issue is that the original methods are not thread-safe, why is ThreadStatic used in the demo?

3 个答案:

答案 0 :(得分:0)

The focus is on the line that creates a new StringBuilder instance. The code causes an allocation for sb.ToString() and internal allocations within the StringBuilder implementation, but you cannot control those allocations if you want the string result.

Well according to example, they ignored their own words. Better would be to just cache it and reuse it (clean it before use). No allocations except those what is needed:

// assume bgrImage is your image from the server
let rgbImage = OpenCVWrapper.rgbImage(fromBGR: bgrImage)
// double check the syntax on this ^ I'm not 100% sure how the bridging header will convert it

Also, I think this is bery bad example of how GC can harm your application performance. Temporal and short string is basicaly never enter 2nd generation and will be disposed shortly. Better would be something like buffers for WCF transfer streams, with returning this buffer in pool, or how Task works in general (same idead) and allocate their intestines, but not StringBuilder, duh.

答案 1 :(得分:0)

Here is the answer to "original methods are not thread-safe"

Basically, what author done is - marked property with ngSubmit, which makes it thread safe because value will be avail only for this thread. Different thread will have different value/reference. And this "cache" will live only for the duration of the life of the thread itself. Even if the method itself is not thread-safe, the value it accesses is.

Now, I don't think, it is generally a great example because what is the sense of this? You keep around an instance of sting builder that you clean out anyway.

If your particular interest in per thread static value, GET is nice thing to have. If you more interested in thread safe static methods, look into @Directive({ selector: '[appPreventDoubleClick]' }) export class PreventDoubleClickDirective { private alreadyClicked = false; constructor( private elementRef: ElementRef ) { } @HostListener('click', [ '$event' ]) onClick(event: MouseEvent): void { this.handleClick(event); } private handleClick(event: MouseEvent): void { if (this.alreadyClicked) { event.preventDefault(); } else { this.alreadyClicked = true; } } }

ThreadStaticAttribute

答案 2 :(得分:0)

此示例仅显示主要想法,并且不会潜入太深。让我们用新方法扩展我们的类以添加命名空间。

public string GenerateFullTypeName(string name, int arity, string @namespace)
{
    StringBuilder sb = AcquireBuilder();
    sb.Append(this.GenerateNamespace(@namespace));
    sb.Append(this.GenerateFullTypeName(name, arity));
    return GetStringAndReleaseBuilder(sb);
}

public string GenerateNamespace(string @namespace)
{
    StringBuilder sb = AcquireBuilder();

    sb.Append(@namespace);
    sb.Append(".");

    return GetStringAndReleaseBuilder(sb);
}

并测试Console.WriteLine(test.GenerateFullTypeName("SomeType", 3, "SomeNamespace"));原始代码按预期工作(输出  字符串是SomeNamespace.SomeType<T1, T2, T3>),但如果我们应用“优化”会发生什么?输出字符串是错误的(SomeType<T1, T2, T3>SomeType<T1, T2, T3>),因为我们只对该类中的所有方法使用StringBuilder的一个(实例化)实例,即使此实例仍在使用中。这就是为什么实例仅在使用后存储在字段中,如果再次使用则从字段中删除。