建站学 - 轻松建站从此开始!

建站学-个人建站指南,网页制作,网站设计,网站制作教程

当前位置: 建站学 > 网站开发 > asp.net教程 >

asp.net的LRU缓存的实现算法讨论(2)

时间:2009-07-23 21:19来源: 作者: 点击:
测试模型中每秒钟的读和写的比例是 7:3 ,以下是依次在 3 个时间点截取的性能计数器图。 图1 图2 图3 内存最高会达到 1g , cpu 也平均百分之 90 以上,但测试到后期会发现每隔一段时间,就会有一两秒,吞吐量为 0

测试模型中每秒钟的读和写的比例是7:3,以下是依次在3个时间点截取的性能计数器图。
图1

 
图2

 

 
图3

 


内存最高会达到
1gcpu也平均百分之90以上,但测试到后期会发现每隔一段时间,就会有一两秒,吞吐量为0,如最后一张截图,后来观察发现,停顿的那一两秒是二代内存在回收,等不停顿的时候# gen 2 collections就会加1,这个原因应该是链表引起的,对链表中节点的添加和删除是很耗费GC的,因为会频繁的创建和销毁对象。 

后续改进

1、 用游标链表来代替普通的双头链表,程序起来就收工分配固定大小的数组,然后用数组的索引来做链表,省得每次添加和删除节点都要GC的参与,这相当于手工管理内存了,但目前我还没找到c#合适的实现。

2、 有人说链表不适合用在多线程环境中,因为对链表的每个操作都要加互斥锁,连读写锁都用不上,我目前的实现是直接用互斥锁做的线程同步,每秒的吞吐量七八十万,感觉lock也不是瓶颈,如果要改进的话可以把DictionaryThreadSafelyDictionary来代替,然后链表还用互斥锁(刚开始设想的链表操作只锁要操作的几个节点以降低并发冲突的想法应该不可取,不严谨)。

3、 还有一个地方就是把锁细分以下,链表还用链表,但每个链表的节点是个HashSet,对HashSet的操作如果只有读,写,删,没有遍历的话应该不需要做线程同步(我感觉不用,因为Set就是一个集合,一个线程往里插入,一个线程往里删除,一个线程读取应该没问题,顶多读进来的数据可能马上就删除了,而整个Set的结构不会破坏)。然后新增数据的时候往链表头顶Set里插入,读取某个数据的时候把它所在的节点的Set里删除该数据,然后再链表头的Set里插入一个数据,这样反复操作后,链表的最后一个节点的Set里的数据都是旧数据了,可以安全的删除了,当然这个删除的时候应该是要锁整个链表的。每个Set应该有个大小上限,比如20w,但set不能安全的遍历,就不能得到当前大小,所以添加、删除Set的数据的时候应该用Interlocked.Decrement() Interlocked.Increment()维护一个Count,一遍一个Set满的时候,再到链表的头新增一个Set节点。

性能测试脚本

class Program {
    
private static PerformanceCounter _addCounter;
    
private static PerformanceCounter _getCounter;
 
    
static void Main(string[] args) {
        SetupCategory();
        _addCounter 
= new PerformanceCounter("wawasoft.lrucache""add/sec"false);
        _getCounter 
= new PerformanceCounter("wawasoft.lrucache""get/sec"false);
        _addCounter.RawValue 
= 0;
        _getCounter.RawValue 
= 0;
 
        Random rnd 
= new Random();
        
const int max = 500 * 10000;
 
 
        LRUCacheHelper
<intint> cache = new LRUCacheHelper<intint>(200 * 10000, max);
 
        
for (int i = 10000*100000 - 1; i >= 0; i--)
        {
            
if(i % 10 > 7)
            {
                ThreadPool.QueueUserWorkItem(
                    
delegate
                        {
                            cache.Add(rnd.Next(
010000), 0);
                            _addCounter.Increment(); 
                        });
            }
            
else
            {
                ThreadPool.QueueUserWorkItem(
                   
delegate
                   {
                       
int pop = cache.Get(i);
                       _getCounter.Increment();
                   });
            }
        }
        Console.ReadKey();
    }
 
    
private static void SetupCategory() {
        
if (!PerformanceCounterCategory.Exists("wawasoft.lrucache")) {
 
            CounterCreationDataCollection CCDC 
= new CounterCreationDataCollection();
 
            CounterCreationData addcounter 
= new CounterCreationData();
            addcounter.CounterType 
= PerformanceCounterType.RateOfCountsPerSecond32;
            addcounter.CounterName 
= "add/sec";
            CCDC.Add(addcounter);
 
 
            CounterCreationData getcounter 
= new CounterCreationData();
            getcounter.CounterType 
= PerformanceCounterType.RateOfCountsPerSecond32;
            getcounter.CounterName 
= "get/sec";
            CCDC.Add(getcounter);
 
            PerformanceCounterCategory.Create(
"wawasoft.lrucache","lrucache",CCDC);
 
        }
    }
 
}
(责任编辑:admin)
织梦二维码生成器
顶一下
(0)
0%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片