使用ThreadStatic取代昂贵的当地人 - 好主意吗? [英] Using ThreadStatic to replace expensive locals -- good idea?

查看:144
本文介绍了使用ThreadStatic取代昂贵的当地人 - 好主意吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

更新:因为我所料,在回答这个问题了社会各界的中肯的意见是,衡量一下,看看 <一href="http://stackoverflow.com/questions/4864974/using-threadstatic-to-replace-expensive-locals-good-idea/4865914#4865914">chibacity贴有一些非常不错的测试,这样做是对我一个答案;同时,我写我自己的测试;我看到的性能差异竟是如此巨大,<一个href="http://philosopherdeveloper.com/posts/replacing-expensive-locals-with-threadstatic-fields.html"相对=nofollow>我觉得有必要写一个关于它的博客文章。

Update: as I should have expected, the community's sound advice in response to this question was to "measure it and see." chibacity posted an answer with some really nice tests that did this for me; meanwhile, I wrote a test of my own; and the performance difference I saw was actually so huge that I felt compelled to write a blog post about it.

不过,我也承认<一个href="http://stackoverflow.com/questions/4864974/using-threadstatic-to-replace-expensive-locals-good-idea/4865784#4865784">Hans's 的解释是, ThreadStatic 属性确实不是免费的,实际上依赖于CLR的辅助方法,以发挥其作用。这使得它远不是显而易见,是否有适当的优化在任意情况下适用。

However, I should also acknowledge Hans's explanation that the ThreadStatic attribute is indeed not free and in fact relies on a CLR helper method to work its magic. This makes it far from obvious whether it would be an appropriate optimization to apply in any arbitrary case.

对我来说,好消息是,在的情况下,它似乎已经取得了很大的进步。

The good news for me is that, in my case, it seems to have made a big improvement.

我有一个方法,(在许多其他事情)实例化一些中等大小的数组(约50元)几局部变量。

I have a method which (among many other things) instantiates some medium-size arrays (~50 elements) for a few local variables.

在一些分析我已经确定了这种方法的东西的性能瓶颈。这并不是说该方法需要极长的时间来调用;相反,它是简单地称为的许多的时候,(几十万到数百万次的会议,这将是几个小时),非常快。因此,即使其性能相对小的改进应该是值得的。

After some profiling I've identified this method as something of a performance bottleneck. It isn't that the method takes an extremely long time to call; rather, it is simply called many times, very quickly (hundreds of thousands to millions of times in a session, which will be several hours). So even relatively small improvements to its performance should be worthwhile.

我突然想到的,而不是在每次调用分配一个新的数组,也许,我可以用域标记 [ThreadStatic] ;每当该方法被调用时,它会检查是否该字段在当前线程上初始化,如果没有,则进行初始化。从上同一线程的所有呼叫点将有一个数组都准备好,在这一点上。

It occurred to me that maybe instead of allocating a new array on each call, I could use fields marked [ThreadStatic]; whenever the method is called, it will check if the field is initialized on the current thread, and if not, initialize it. From that point on all calls on the same thread will have an array all ready to go at that point.

(该方法初始化数组本身中的每个元素,所以具有阵列中的过时的元素不应该是一个问题。)

(The method initializes every element in the array itself, so having "stale" elements in the array should not be an issue.)

我的问题很简单:这个问题似乎是一个好主意?是否有陷阱,使用这种方式 ThreadStatic 属性(即,作为一个性能优化,以减轻实例化的局部变量的新对象的成本),我应该知道的?是一个 ThreadStatic 字段本身的性能可能不是很大;例如,有很多额外的东西发生的背景,有自己的一套的成本,以使此功能可能吗?

My question is simply this: does this seem like a good idea? Are there pitfalls to using the ThreadStatic attribute in this way (i.e., as a performance optimization to mitigate the cost of instantiating new objects for local variables) that I should know about? Is the performance of a ThreadStatic field itself perhaps not great; e.g., is there a lot of extra "stuff" happening in the background, with its own set of costs, to make this feature possible?

这也是非常合理的,我认为我错了,甚至尝试优化的东西便宜(?)作为一个50元素的数组,如果这是这样,肯定是让我知道,但是的一般的问题仍然成立。

It's also quite plausible to me that I'm wrong to even try to optimize something as cheap (?) as a 50-element array—and if that's so, definitely let me know—but the general question still holds.

推荐答案

我已经进行了一个简单的基准和 ThreadStatic 执行中的问题描述的简单参数更好。

I have carried out a simple benchmark and ThreadStatic performs better for the simple parameters described in the question.

由于有许多算法,具有较高的迭代次数,我怀疑这是GC开销顺利的情况下杀死它为其分配新阵列的版本:

As with many algorithms which have a high number of iterations, I suspect it is a straightforward case of GC overhead killing it for the version which allocates new arrays:

更新

通过测试,包括阵列的增加迭代模型最小的阵列参考使用,加上 ThreadStatic 数组引用的使用除了previous测试,其中提到了复制地方:

With tests that include an added iteration of the array to model minimal array reference use, plus ThreadStatic array reference usage in addition to previous test where reference was copied local:

Iterations : 10,000,000

Local ArrayRef          (- array iteration) : 330.17ms
Local ArrayRef          (- array iteration) : 327.03ms
Local ArrayRef          (- array iteration) : 1382.86ms
Local ArrayRef          (- array iteration) : 1425.45ms
Local ArrayRef          (- array iteration) : 1434.22ms
TS    CopyArrayRefLocal (- array iteration) : 107.64ms
TS    CopyArrayRefLocal (- array iteration) : 92.17ms
TS    CopyArrayRefLocal (- array iteration) : 92.42ms
TS    CopyArrayRefLocal (- array iteration) : 92.07ms
TS    CopyArrayRefLocal (- array iteration) : 92.10ms
Local ArrayRef          (+ array iteration) : 1740.51ms
Local ArrayRef          (+ array iteration) : 1647.26ms
Local ArrayRef          (+ array iteration) : 1639.80ms
Local ArrayRef          (+ array iteration) : 1639.10ms
Local ArrayRef          (+ array iteration) : 1646.56ms
TS    CopyArrayRefLocal (+ array iteration) : 368.03ms
TS    CopyArrayRefLocal (+ array iteration) : 367.19ms
TS    CopyArrayRefLocal (+ array iteration) : 367.22ms
TS    CopyArrayRefLocal (+ array iteration) : 368.20ms
TS    CopyArrayRefLocal (+ array iteration) : 367.37ms
TS    TSArrayRef        (+ array iteration) : 360.45ms
TS    TSArrayRef        (+ array iteration) : 359.97ms
TS    TSArrayRef        (+ array iteration) : 360.48ms
TS    TSArrayRef        (+ array iteration) : 360.03ms
TS    TSArrayRef        (+ array iteration) : 359.99ms

code:

Code:

[ThreadStatic]
private static int[] _array;

[Test]
public object measure_thread_static_performance()
{
    const int TestIterations = 5;
    const int Iterations = (10 * 1000 * 1000);
    const int ArraySize = 50;

    Action<string, Action> time = (name, test) =>
    {
        for (int i = 0; i < TestIterations; i++)
        {
            TimeSpan elapsed = TimeTest(test, Iterations);
            Console.WriteLine("{0} : {1:F2}ms", name, elapsed.TotalMilliseconds);
        }
    };

    int[] array = null;
    int j = 0;

    Action test1 = () =>
    {
        array = new int[ArraySize];
    };

    Action test2 = () =>
    {
        array = _array ?? (_array = new int[ArraySize]);
    };

    Action test3 = () =>
    {
        array = new int[ArraySize];

        for (int i = 0; i < ArraySize; i++)
        {
            j = array[i];
        }
    };

    Action test4 = () =>
    {
        array = _array ?? (_array = new int[ArraySize]);

        for (int i = 0; i < ArraySize; i++)
        {
            j = array[i];
        }
    };

    Action test5 = () =>
    {
        array = _array ?? (_array = new int[ArraySize]);

        for (int i = 0; i < ArraySize; i++)
        {
            j = _array[i];
        }
    };

    Console.WriteLine("Iterations : {0:0,0}\r\n", Iterations);
    time("Local ArrayRef          (- array iteration)", test1);
    time("TS    CopyArrayRefLocal (- array iteration)", test2);
    time("Local ArrayRef          (+ array iteration)", test3);
    time("TS    CopyArrayRefLocal (+ array iteration)", test4);
    time("TS    TSArrayRef        (+ array iteration)", test5);

    Console.WriteLine(j);

    return array;
}

[SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods", MessageId = "System.GC.Collect")]
private static TimeSpan TimeTest(Action action, int iterations)
{
    Action gc = () =>
    {
        GC.Collect();
        GC.WaitForFullGCComplete();
    };

    Action empty = () => { };

    Stopwatch stopwatch1 = Stopwatch.StartNew();

    for (int j = 0; j < iterations; j++)
    {
        empty();
    }

    TimeSpan loopElapsed = stopwatch1.Elapsed;

    gc();
    action(); //JIT
    action(); //Optimize

    Stopwatch stopwatch2 = Stopwatch.StartNew();

    for (int j = 0; j < iterations; j++) action();

    gc();

    TimeSpan testElapsed = stopwatch2.Elapsed;

    return (testElapsed - loopElapsed);
}

这篇关于使用ThreadStatic取代昂贵的当地人 - 好主意吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆