热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Interlocked.Exchange<T>比Interlocked.CompareExchange<T>慢?

如何解决《Interlocked.Exchange<T>比Interlocked.CompareExchange<T>慢?》经验,为你挑选了1个好方法。

在优化程序时,我遇到了一些奇怪的性能结果,这些结果显示在以下BenchmarkDotNet基准测试中:

string _s, _y = "yo";

[Benchmark]
public void Exchange() => Interlocked.Exchange(ref _s, null);

[Benchmark]
public void CompareExchange() => Interlocked.CompareExchange(ref _s, _y, null);

结果如下:

BenchmarkDotNet=v0.10.10, OS=Windows 10 Redstone 3 [1709, Fall Creators Update] (10.0.16299.192)
Processor=Intel Core i7-6700HQ CPU 2.60GHz (Skylake), ProcessorCount=8
Frequency=2531248 Hz, Resolution=395.0620 ns, Timer=TSC
.NET Core SDK=2.1.4
  [Host]     : .NET Core 2.0.5 (Framework 4.6.26020.03), 64bit RyuJIT
  DefaultJob : .NET Core 2.0.5 (Framework 4.6.26020.03), 64bit RyuJIT

          Method |      Mean |     Error |    StdDev |
---------------- |----------:|----------:|----------:|
        Exchange | 20.525 ns | 0.4357 ns | 0.4662 ns |
 CompareExchange |  7.017 ns | 0.1070 ns | 0.1001 ns |

这似乎Interlocked.Exchange是两倍慢Interlocked.CompareExchange- 这是令人困惑的,因为它应该做的工作少.除非我错了,否则两者都应该是CPU操作.

有没有人对这可能发生的原因有一个很好的解释?这是CPU操作中的实际性能差异还是.NET Core包装它们的方式中的一些问题?

如果是这种情况,最好是尽可能避免Interlocked.Exchange()和使用Interlocked.CompareExchange()

编辑:另一件奇怪的事情:当我使用int或long而不是字符串运行相同的基准测试时,我或多或少地获得相同的运行时间.另外,我使用BenchmarkDotNet的反汇编诊断程序来查看正在生成的程序集,并发现了一些有趣的内容:使用int/long版本我可以清楚地看到xchg和cmpxchg指令,但是我看到调用了Interlocked.Exchange/Interlocked的字符串. CompareExchange方法......!

EDIT2:coreclr中已解决的问题:https://github.com/dotnet/coreclr/issues/16051



1> InBetween..:

跟进我的评论,这似乎是通用重载的一个问题Exchange.

如果你完全避免了泛型重载(改变的类型_s_yobject),性能差异消失.

问题仍然存在,为什么解决通用重载只会减慢速度Exchange.通过阅读Interlocked源代码,似乎实现了一个hack CompareExchange以使其更快.关注的源代码评论CompareExchange:

 * CompareExchange
 * 
 * Notice how CompareExchange() uses the __makeref keyword
 * to create two TypedReferences before calling _CompareExchange().
 * This is horribly slow. Ideally we would like CompareExchange()
 * to simply call CompareExchange(ref Object, Object, Object); 
 * however, this would require casting a "ref T" into a "ref Object", 
 * which is not legal in C#.
 * 
 * Thus we opted to cheat, and hacked to JIT so that when it reads
 * the method body for CompareExchange() it gets back the
 * following IL:
 *
 *     ldarg.0 
 *     ldarg.1
 *     ldarg.2
 *     call System.Threading.Interlocked::CompareExchange(ref Object, Object, Object)
 *     ret
 *
 * See getILIntrinsicImplementationForInterlocked() in VM\JitInterface.cpp
 * for details.

没有类似的东西被评论,Exchange它也使用"非常慢",__makeref所以这可能是你看到这种意外行为的原因.

所有这些当然是我的解释,你实际上需要.NET团队的某个人来确认我的怀疑.


推荐阅读
author-avatar
n张家珲
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有