小编ric*_*ice的帖子

C#Dictionary性能:默认字符串Comparer的GetHashCode()违反指南分配内存,从而破坏性能?

一个既定的准则,即获取哈希码不应该分配内存,因为这将通过调用垃圾收集器对哈希表查找产生负面影响.

然而,这种确切的失败是我看到我使用System.Collections.Generic.Dictionary我的应用程序的概况

在非常紧凑的循环中,我在我的分析器结果中找到以下内容:

  • [3.47%] TryGetValue(TKey,TValue&)(...字典)
    • [3.47%] FindEntry(TKey)(...字典)
      • [3.47%] GetHashCode(string)(System.CultureAwareComparer)
        • [3.46%] GetHashCodeOfString(String,CompareOptions)(System.Globalization.CompareInfo)
          • [3.39%] [垃圾收集]
          • [0.01%] [线程悬空]

这是分析器的整个子树会计.

我不是这种特殊工作的经验丰富的专家,所以我可能会错误地阅读这些茶叶.但它看起来像GetHashCodeOfString"必须"分配内存并邀请垃圾收集器在这个循环的中间中断我的程序我想要真正的调整和紧,这是占这个循环的惊人的大部分成本.

顺便说一句,这里有一个额外的证据表明这个代码分配了内存

我的下一步是使用序数比较器初始化Dictionary并重新运行我的测试.

但我想知道围绕这个问题是否存在现有的智慧.看起来像带有字符串键的字典很常见,并且可以很好地探索这种常见事物的成本.我发现了以下分析,但它侧重于实际比较作为祸患的原因,而不是分配内存的哈希码方法.

任何人都可以建议使用字符串键的字典的正确方法,以避免这个问题?

我有的具体问题包括:

  • 如果我使用序数比较器,分配会消失吗?
  • 如果没有,我是否需要编写自己的比较器,这会使分配消失吗?
  • 如果我确实让比较器消失了,根据我开始的MSFT推荐链接,我真的可以期待真正的改进吗?

编辑:Crud,我的坏,但这不是默认的比较器属性,我们将它设置为ignoreCase.不确定这是否会影响结果,但由于ignoreCase会影响相等性,因此必须对哈希产生一些影响.

更新:使用序数比较器(仍然使用IgnoreCase)进行另一个测试,并将原始结果输出重新设置为100%cost = TryGetValue,这样它就会更多苹果到苹果

原版的:

  • 100%TryGetValue
    • 100%FindEntry
      • 99.5%CultureAwareComparer.GetHashCode
        • 99.5%CompareInfo.GetHashCodeOfString
          • 95.86%[垃圾收集]
          • 3.31%[线程暂停]
      • 0.5%CultureAwareComparer.Equals
        • 0.5%比较
          • 0.5%[垃圾收集]

序:

  • 100%TryGetValue
    • 100%FindEntry
      • 47.22%CultureAwareComparer.Equals
        • 47.22%[垃圾收集]

TryGetValue的总花费时间也显着减少.我不小心确保所有其他方面都相同,但在第一次运行的10分钟压力测试中这占了46秒,而在orindal运行中它占了252毫秒.考虑一下轶事,而不是预期的相对成本.

看起来哈希的全部成本(曾经是成本的99%以上)现在是如此"自由",甚至不能出现在探查器中,我认为它在采样模式下运行.

我猜这个街道上的这个词你应该使用序数比较.

我仍然无法向自己说明为什么GC成本对第一个配置文件结果的贡献如此之大,但是从下面的评论中我想我必须相信它不会分配托管堆内存,但是因为它很慢,所以它倾向于是由其他线程上的其他活动"随机"GC的函数,因为此进程确实使用服务器模式gc.

也许这表明这个紧密循环往往与其他地方的分配快乐代码并发.

c# string performance dictionary

16
推荐指数
1
解决办法
3046
查看次数

C# - 是否可以装箱?

Boxing将值类型转换为对象类型.或者正如MSDN所说,装箱是一种"将结构包装在托管堆上的引用类型对象中的操作".

但是如果你试着通过查看IL代码来深入研究,那么你只能看到神奇的单词"box".

猜测,我猜运行时有一些基于泛型的秘密类,就像Box<T>一个public T Value属性一样,而装箱的int看起来像:

int i = 5;
Box<int> box = new Box<int>;
box.Value = 5;
Run Code Online (Sandbox Code Playgroud)

拆箱int会便宜得多: return box.Value;

不幸的是,我的性能饥渴的服务器应用程序做了相当多的拳击,特别是小数.更糟糕的是,这些盒子是短暂的,这使我怀疑我支付了两次,一次用于装箱,然后再用于垃圾收集箱完成之后.

如果我自己解释这个内存,我会考虑在这里使用一个对象池.但由于实际的对象创建隐藏在IL中的魔术词后面,我有哪些选择?

我的具体问题:

  • 是否存在一种诱导运行时从池中取出盒子而不是实例化它们的现有机制?
  • 拳击期间创建的实例的类型是什么?是否可以手动控制装箱过程,但仍然可以与拆箱兼容?

如果最后一个问题看起来很奇怪,我的意思是我可以创建我自己的Box<T>DecimalBox类,汇集它,并手动打开/取消框.但是我不想去修改代码中消耗盒装值的各个地方(也就是unbox它).

c# boxing memory-management

12
推荐指数
1
解决办法
778
查看次数

ViewModel是否应该传递DependencyProperties并绑定到Model上的DependencyProperties?

我是WPF/MVVM的新手,我发现的例子似乎并没有涵盖我所面临的问题.

我有一个用于管理相当复杂的业务配置对象的屏幕.在MVVM中,我认为这意味着我应该拥有以下内容:

  1. 具有接近零逻辑的XAML视图
  2. 具有屏幕逻辑的ViewModel类
  3. 我通常的业务类充当了Model的角色,拥有所有业务逻辑

在我的情况下,有业务规则说我的业务类fieldA的更改可能有各种副作用,例如更改fieldB的值,或填充整个子对象列表.

我可能是错的,但我认为我应该将这些规则封装在业务类中,因为这些规则实际上并不是关于屏幕的实体.

当然,这些副作用需要立即回到屏幕上.

因此,从用户的角度来看,他可能会编辑fieldA,并在View上看到fieldB更新.

我理解如何从View到ViewModel进行数据绑定.

但就我而言,似乎我需要两层数据绑定:一个在View和ViewModel之间,另一个在ViewModel和Model之间.

鉴于我有两次基本相同的问题,我认为应该适用一种解决方案.所以我将我的Model类变成了DependencyObject,并将其属性设置为DependencyProperties.

以fieldA为例,它将出现在所有三个层中:

  1. 作为可视组件数据绑定到ViewModel.FieldA,例如text ="{Binding FieldA,Mode = TwoWay}"
  2. ViewModel作为DependencyProperty绑定到"向上"到View,并"向下"到Model
  3. 模型作为DependencyProperty

我不想通过跳过第2部分将我的View XAML直接耦合到业务对象,这对我来说似乎不是一个干净的模式应用程序.也许这是错误的.

我本质上似乎需要在我的ViewModel中使用"传递DependencyProperty".

我的问题:

  • 这是正确的一般方法还是我认为这一切都错了?
  • 有没有使用这种传递方法的例子?
  • 有人能给出一个代码示例,说明在ViewModel和Model FieldA DependencyProperties之间创建传递绑定的正确方法吗?

c# wpf mvvm

5
推荐指数
1
解决办法
626
查看次数

标签 统计

c# ×3

boxing ×1

dictionary ×1

memory-management ×1

mvvm ×1

performance ×1

string ×1

wpf ×1