专栏首页walterlv - 吕毅的博客.NET/C# 推荐一个我设计的缓存类型(适合缓存反射等耗性能的操作,附用法)

.NET/C# 推荐一个我设计的缓存类型(适合缓存反射等耗性能的操作,附用法)

.NET/C# 推荐一个我设计的缓存类型(适合缓存反射等耗性能的操作,附用法)

发布于 2018-09-02 14:27 更新于 2018-09-02 07:59

这里我想说的是类型“实例”的缓存,适用于那些实例或者值计算很耗时的操作。典型的场景如反射获取 Attribute


适用

本文推荐的方法适用于相同的输入可以获得相同的输出,但是这个输入到输出的过程非常耗时。

大家都知道反射是很耗时的,尤其是获取 Attribute 和反射调用实例的方法。而从一个反射的成员中得到其 Attribute 是唯一的输入对应唯一的输出。

思路

既然唯一的输入对应唯一的输出,那么我们可以通过一个字典来储存我们已经转换过的输出。

// 其中 TSource 表示输入的类型,TCache 表示输出的类型。
Dictionary<TSource, TCache> _cacheDictionary = new Dictionary<TSource, TCache>();

然后我们把已经计算过输出的输入存入到这个字典中。这样,当我们试图重新计算相同输入的输出的时候,便可以直接从字典中取得所需的输出的值。

为了通用一点,我设计一个类型 CachePool<TSource, TCache>

namespace Walterlv
{
    public sealed class CachePool<TSource, TCache>
    {
        Dictionary<TSource, TCache> _cacheDictionary = new Dictionary<TSource, TCache>();

        private TCache GetOrCacheValue(TSource source)
        {
            // 从这里计算新值或者从字典中获取已经计算的值。
        }
    }
}

这个计算过程是唯一确定的,所以我们可以从构造函数中传入并储存下来。

public CachePool([NotNull] Func<TSource, TCache> conversion)
{
    _convert = conversion ?? throw new ArgumentNullException(nameof(conversion));
}

private readonly Func<TSource, TCache> _convert;

于是我们的缓存类已经近乎完成。为了线程安全,我加了锁;但考虑到部分情况下性能更重要,所以我把锁设为了可选项。

代码

代码我放到了 gist.github.comwalterlv/CachePool.cs

你可以直接点击以上链接查看。为了不影响本文的阅读,我把实际的代码放到了最后。

用法

高性能创建对象

比如你认为反射创建对象是一个耗时的操作,那么可以将构造函数的调用创建成一个委托,然后把这个委托缓存下来。这样,下次创建相同对象的时候就不需要反射调用构造函数了,而是直接调用委托拿到对象的新实例。

private static readonly CachePool<Type, Func<object>> ConstructorCache =
    new CachePool<Type, Func<object>>(x =>
        Expression.Lambda<Func<object>>(Expression.New(x)).Compile());

高性能为属性赋值

我在 如何快速编写和调试 Emit 生成 IL 的代码 一文中创建了可以为属性赋值的委托,你也可以使用此方法将委托缓存下来,以便每次给相同类型的相同属性赋值时能有不那么差的性能。

高性能“反射”调用函数

调用函数所得的结果可是不一样的,所以直接缓存函数结果是不靠谱的,不过我们依然可以将反射调用缓存为委托的调用。我在 .NET Core/Framework 创建委托以大幅度提高反射调用的性能 一文中有介绍。

附代码

本文会经常更新,请阅读原文: https://walterlv.com/post/design-a-cache-pool.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。

本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名 吕毅 (包含链接: https://walterlv.com ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系 (walter.lv@qq.com)

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 为 WPF 程序添加 Windows 跳转列表的支持

    Windows 跳转列表是自 Windows 7 时代就带来的功能,这一功能是跟随 Windows 7 的任务栏而发布的。当时应用程序要想用...

    walterlv
  • .NET/C# 使用反射注册事件

    2018-09-01 12:31

    walterlv
  • 让控制台支持 ANSI 转义序列,输出下划线、修改颜色或其他控制

    发布于 2018-08-05 06:24 更新于 2018-09...

    walterlv
  • 使用Kotlin 1.1.5 的REPL 来简单分析一下Java 9 中的$ jmod list java.base.jmod《Kotlin极简教程》正式上架:

    命令行列出了 模块 java.base.jmod 中所有文件(.class文件, .dat, .jar, .cfg, .dylib 等 )共 5761个文件...

    一个会写诗的程序员
  • 部署Amoeba3.X实现Mysql读写

       Amoeba for Mysql软件,致力于MySQL的分布式数据库前端代理层,它主要在应用层访问MySQL的时候充当SQL路由功能,专注于分布式数据库...

    py3study
  • 用NumPy写深度模型,用Julia可微分编程写函数,这是WAIC开发者日

    WAIC 世界人工智能大会已于近日在上海开幕。在昨天由机器之心承办的开发者日主单元上,阿里技术副总裁贾扬清、亚马逊机器学习副总裁 Alex Smola、百度 A...

    机器之心
  • Servlet 通过Filter拦截器解决全站编码问题

    请求 参数 public string import void 编码 问题 utf-8 request matcher

    Alone88
  • Intent传递对象的两种方法

    听着music睡
  • 屏幕录像专家2019 Build0608 完全去水印破解版

    屏幕录像专家是一款专业的屏幕录像制作工具。使用它可以轻松地将屏幕上的软件操作过程、网络教学课件、网络电视、网络电影、聊天视频、游戏等录制成FLASH动画、WMV...

    萌海无涯
  • 全量开放合成音频平台,用户零门槛接入

    ? 9月3日,腾讯云语音合成团队正式开放面向全量用户的合成音频平台,该平台可以帮助用户零门槛借助语音合成技术生成一段个性化音频,为音视频行业内容创作提供更为快...

    腾讯云AI中心

扫码关注云+社区

领取腾讯云代金券