首页 > 解决方案 > 为什么使用 ThreadLocal 的 Value 成员的本地副本更快,尽管它是一个引用类型?

问题描述

我正在关注并行编程模式第 107 页上的示例:使用 .NET Framework 4 理解和应用并行模式(https://www.microsoft.com/en-us/download/details.aspx?id=19222)。据说使用 ThreadLocal 的 Value 成员的本地副本比使用 Threadlocal.Value 本身更快。我对此进行了测试,确实如此。但为什么?

从代码中可以看出,_vector2.Value 的本地副本保存在 vector2 中,该本地副本用于对所有项目求和。如果您使用 _vector2.Value[i] += _vector1.Value[i] 而不是 vector2[i] += vector1[i] 代码运行,尽管速度较慢。这就是文章中所说的。现在 int[] 是一个引用类型。这意味着当您在 vector2 中进行复制时,您实际上是在复制 ThreadLocal 的 Value 成员中原始 int[] 的引用。注释掉证实了这一点_vector2.Value = vector2。打印结果保持不变。所以,我认为不需要这个任务。

现在,由于 _vector2.Value 和 vector2 引用相同的数据,使用本地副本 (vector2) 怎么可能更快?在我的测试中快了大约 4 倍。有谁知道我错过了什么?

    class ReferenceList
    {
        const int VECTOR_LENGTH = 100000000;
        private ThreadLocal<int[]> _vector1 = new ThreadLocal<int[]>(() => Enumerable.Range(1, VECTOR_LENGTH).ToArray());
        private ThreadLocal<int[]> _vector2 = new ThreadLocal<int[]>(() => Enumerable.Range(1, VECTOR_LENGTH).ToArray());

        internal void DoWork()
        {
            int[] vector1 = _vector1.Value;
            int[] vector2 = _vector2.Value;

            for (int i = 0; i < VECTOR_LENGTH; i++)
            {
                // This is the fast way (as in the document)
                vector2[i] += vector1[i];

                // This is the slow way
                //_vector2.Value[i] += _vector1.Value[i];
            }

            // Since int[] is a reference type. This step is not needed, I think. The result is not influenced when commenting out this line
            _vector2.Value = vector2;

            Console.WriteLine($"Thread-{Thread.CurrentThread.ManagedThreadId} Result: {String.Join(", ", _vector2.Value.Take(10))}");
        }

标签: c#multithreading

解决方案


vector1是对数组的直接引用。没有什么比这更快了。

_vector1不是数组的直接引用。_vector1.Value产生相同的值 - 但根据源代码,需要付出一些努力才能获得该值。因此,每次您要求.Value您再次接受(执行方法等)性能损失时(即使知道它会返回相同的值,也需要付出一些努力才能解决)。这忽略了其他相关成本,例如可能减少数据局部性、增加缓存未命中等。


推荐阅读