ASP页面级缓存

很早以前的一个想法及实现方式,因为当时有过一套系统是使用ASP实现,中间也有过性能优化。在考虑到成本时,只对部分页面进行缓存处理,从而提升性能。

在ASP.NET下面,很容易利用一些static方式来做页面级别缓存效果非常好,而模拟static实现方式是最直接方案。而在ASP平台下除了Application、Session对象是把数据存储在内存当中,以下我分析两种方式的利弊。

Session对象

Session自身是以用户级会话方式,所以把其作为缓存很明显只是对当前用户有效,而页面部分数据其实是所有人都共同拥有的,光这一点很难把Session对象当做页面级缓存存储对象。

并大概会遇到以下几种麻烦点:

  1. 用户级会员,仅对当前用户有效。
  2. 当工作在多进程存在时,命中率是一个问题。
  3. 有效期。
  4. 不存在锁问题。

Application对象

以Session相比较Application是应用级存储空间,换言之,只要存在任何页面都可以调用到,并且不存在工作在多进程无法共享问题。

而接下来我们得考虑数据更新问题,因为这类数据并非一层不变,页面级数据更新大概有两种方式:

  • 程序调度
  • 用户触发

程序调度来对于ASP.NET来说容易得多,利用timer很轻松解决问题。而ASP平台下相对于简单得多只有用户触发和时间点两者结合。

比如我们每10分钟调用一次,缓存数据时记录当前时间,并且当每一次读取数据时对其进行判断是否过期。

因此在这几个问题下面,我封装一个类,大致代码如下:

Class Cls_Cache
    ' 增加
    Public Sub Add(ByVal key, ByVal val, ByVal expire)
        Application.Lock
            Application(key & "_time") = DateAdd("n", expire, Now)
            Application(key) = val
        Application.UnLock
    End Sub

    ' 增加不过期缓存
    Public Sub AddNotExpire(ByVal key, ByVal val)
        Application.Lock
            Application(key) = val
        Application.UnLock
    End Sub

    ' 是否存在
    Public Function Exists(ByVal key)
        Exists = True
        If IsDate(Application(key & "_time")) Then
            ' 过期并做移除处理
            If CDate(Application(key & "_time")) < Now() Then
                Remove(key)
                Exists = False
                Exit Function
            End If
        End If
        Exists = True
    End Function

    ' 获取缓存数据
    Public Function Item(ByVal key)
        If Not Exists(key) Then
            Item = ""
        Else
            Item = Application(key)
        End If
    End Function

    ' 移除
    Public Sub Remove(ByVal key)
        Application.Lock
            Application.Contents.Remove(key & "_time")
            Application.Contents.Remove(key)
        Application.UnLock
    End Sub
End Class

以上并没有做异常处理,弱爆了。而在具体业务逻辑层时,需要做的获取数据,如果数据不存在而读取数据库并重新缓存。

例如:获取点击排行新闻,并且每10分钟自动更新一次。

Function GetHotNews()
    Dim cache, KEY, T
    KEY = "HotNews"
    T = 10
    Set cache = New Cls_Cache
    If Not cache.Exists(KEY) Then
        ' 逻辑处理
        cache.Add KEY, "点击排行新闻"&now(), T
    End If
    GetHotNews = cache.Item(KEY)
End Function

后续

相比较有点繁琐,特别是在代码维护方面,所以我给出个建议。

对于业务逻辑层建议模块化,不建议使用Class来封装大部分业务逻辑,本来目地是页面级缓存,在页面加载时Include到对应的目标文件当中。

以上希望那种还处于ASP时代的朋友有点帮助。

关于ASP四舍五入Round()函数结果不正确

在ASP下面处理四舍五入时我们都会对自带的Round()函数,但是实际上他的四舍五入和我们在数学当中所认识的有所区别,看下面的例子:

Round(1.5)
Round(2.5)
Round(3.5)
Round(4.5)

以上的结果会是什么呢?按我们正常数学当中的四舍五入法依次结果为:2 3 4 5。但是非常抱歉的告诉您,Round()在大于5入、小于5舍、等于5的话奇数弃偶数舍,最终他只会给你:2 2 4 4。那么到底是什么原因促使这样呢?让我给你娓娓道来。

来看一段商家使用“四舍五入”法来针对找零方式,看他们是如何去用数学从中获取的“暴利”,按我们正确理解四舍五入1-4舍(4个数)、5-9入(5个数),按概率来算舍是44.44%、入55.56%,也就是说商家比顾客多11.2%机会,如果将“舍”和“入”相抵那么商家多赚了钱。(PS:以后身上还是多带点零用钱吧,坚持不让这种情况发生)

由于这种“四舍五入”法的不公平,天才们想到了一种叫“四舍六入五成双”相比“四舍五入”是一种精确度的计数保留法。这里“四”是小于五的意思,“六”是大于五的意思,“五”是舍入位之后的尾数逢五的话看前一位,奇进偶不进。

由上面定义我们就知道示例中的结果并不是我日常所见,但是他是结果切是最科学的、最合理的。有人会说了,既然我们日常用惯“四舍五入”法,那我们怎么办?方法当然很多,你可以按四舍五入的定义写个特有方法,而其实有一个更加方便的方式:

FormatNumber()  作为数字被格式化的表达式

FormatNumber(1.5, 0)   ’2
FormatNumber(2.5, 0)   ‘3
FormatNumber(3.5, 0)   ’4
FormatNumber(4.5, 0)   ‘5

格式化数字,而他会比较接近我们“日常四舍五入”法,但是注意他是个数字格式化,所以还是建议您自己一个方法来处理:

Function Round2(ByVal num)
Round2 = Fix(CDbl(num) + 0.5)
End Function

参考文献:

© 2017 卡片机色彩 沪ICP备13032872号-3

Theme by cipchk

to top