14

我编写了小型测试程序,并且很惊讶为什么lock {}解决方案的执行速度比无锁更快,但[ThreadStatic]属性优于静态变量。

[ThreadStatic] 片段:

[ThreadStatic]
private static long ms_Acc;
public static void RunTest()
{
    Stopwatch stopwatch = new Stopwatch();
    stopwatch.Start();
    int one = 1;
    for (int i = 0; i < 100 * 1000 * 1000; ++i) {
        ms_Acc += one;
        ms_Acc /= one;
    }
    stopwatch.Stop();
    Console.WriteLine("Time taken: {0}", stopwatch.Elapsed.TotalSeconds);
}

锁定 {} 片段:

private static long ms_Acc;
private static object ms_Lock = new object();
public static void RunTest()
{
    Stopwatch stopwatch = new Stopwatch();
    stopwatch.Start();
    int one = 1;
    for (int i = 0; i < 100 * 1000 * 1000; ++i) {
        lock (ms_Lock) {
            ms_Acc += one;
            ms_Acc /= one;
        }
    }
    stopwatch.Stop();
    Console.WriteLine("Time taken: {0}", stopwatch.Elapsed.TotalSeconds);
}

在我的机器上,第一个片段需要 4.2 秒;秒 - 3.2 秒,快 1 秒。没有 ThreadStatic 和锁定 - 1.2 秒。

我很好奇为什么[ThreadStatic]这个简单示例中的属性会增加程序执行时间?

更新:我感到非常抱歉,但这些结果是用于DEBUG构建的。一方面RELEASE,我得到了完全不同的数字:(1.2;2.4;1.2)。数字为DEBUG(4.2; 3.2; 1.2)。

因此,对于RELEASE构建似乎没有[ThreadStatic]性能损失。

4

2 回答 2

11

对于 RELEASE 构建,似乎几乎没有 [ThreadStatic] 性能损失(在现代 CPU 上只有轻微损失)。

这是反汇编代码ms_Acc += one; 启用RELEASE优化:

[ThreadStatic]DEBUG

00000060  mov         eax,dword ptr [ebp-40h] 
00000063  add         dword ptr ds:[00511718h],eax 

[ThreadStatic]RELEASE

00000051  mov         eax,dword ptr [00040750h]
00000057  add         eax,dword ptr [rsp+20h]
0000005b  mov         dword ptr [00040750h],eax

[ThreadStatic], DEBUG:

00000066  mov         edx,1 
0000006b  mov         ecx,4616E0h 
00000070  call        664F7450 
00000075  mov         edx,1 
0000007a  mov         ecx,4616E0h 
0000007f  mov         dword ptr [ebp-50h],eax 
00000082  call        664F7450 
00000087  mov         edx,dword ptr [eax+18h] 
0000008a  add         edx,dword ptr [ebp-40h] 
0000008d  mov         eax,dword ptr [ebp-50h] 
00000090  mov         dword ptr [eax+18h],edx 

[ThreadStatic], RELEASE:

00000058  mov         edx,1 
0000005d  mov         rcx,7FF001A3F28h 
00000067  call        FFFFFFFFF6F9F740 
0000006c  mov         qword ptr [rsp+30h],rax 
00000071  mov         rbx,qword ptr [rsp+30h] 
00000076  mov         ebx,dword ptr [rbx+20h] 
00000079  add         ebx,dword ptr [rsp+20h] 
0000007d  mov         edx,1 
00000082  mov         rcx,7FF001A3F28h 
0000008c  call        FFFFFFFFF6F9F740 
00000091  mov         qword ptr [rsp+38h],rax 
00000096  mov         rax,qword ptr [rsp+38h] 
0000009b  mov         dword ptr [rax+20h],ebx 
于 2011-08-23T07:10:19.283 回答
-1

您有两行更新的代码ms_Acc。在这种lock情况下,您对这两者都有一个锁,而在这种ThreadStatic情况下,每次访问都会发生一次ms_Acc,即循环的每次迭代都会发生两次。这通常是使用的好处lock,您可以选择所需的粒度。我猜 RELEASE 构建优化了这种差异。

如果将 for 循环更改为对ms_Acc.

于 2011-08-23T05:42:41.967 回答