List和Dictionary泛型类查找效率存在巨大差异,前段时间亲历了一次。事情的背景是开发一个匹配程序,将书籍(BookID)推荐给网友(UserID),生成今日推荐数据时,有条规则是同一书籍七日内不能推荐给同一网友。
同一书籍七日内不能推荐给同一网友规则的实现是程序不断优化的过程,第一版程序是直接取数据库,根据BookID+UserID查询七日内有无记录,有的话不进行分配。但随着数据量的增大,程序运行时间越来越长,于是开始优化。第一次优化是把所有七日内的数据取出来,放到List<T>中,然后再内存中进行查找,发现这样效率只是稍有提高,但不明显。第二次优化采用了Dictionary<TKey, TValue>,意外的发现效果不是一般的好,程序效率提高了几倍。
下面是伪代码,简化了程序代码,只是为说明List和Dictionary效率的差别,并不具备实际意义。
/// <summary> /// 集合类效率测试 /// </summary> public class SetEfficiencyTest { static List<TestModel> todayList = InitTodayData(); static List<TestModel> historyList = InitHisoryData(); public static void Run() { CodeTimer.Time("ListTest", 1, ListTest); CodeTimer.Time("DictionaryTest", 1, DictionaryTest); } public static void ListTest() { List<TestModel> resultList = todayList.FindAll(re => { if (historyList.Exists(m => m.UserID == re.UserID && m.BookID == re.BookID)) { return false; } return true; }); } public static void DictionaryTest() { Dictionary<int, List<string>> bDic = new Dictionary<int, List<string>>(); foreach (TestModel obj in historyList) { if (!bDic.ContainsKey(obj.UserID)) { bDic.Add(obj.UserID, new List<string>()); } bDic[obj.UserID].Add(obj.BookID); } List<TestModel> resultList = todayList.FindAll(re => { if (bDic.ContainsKey(re.UserID) && bDic[re.UserID].Contains(re.BookID)) { return false; } return true; }); } /// <summary> /// 初始化数据(今日) /// </summary> /// <returns></returns> public static List<TestModel> InitTodayData() { List<TestModel> list = new List<TestModel>(); for (int i = 0; i < 10000; i++) { list.Add(new TestModel() { UserID = i, BookID = i.ToString() }); } return list; } /// <summary> /// 初始化数据(历史) /// </summary> /// <returns></returns> public static List<TestModel> InitHisoryData() { List<TestModel> list = new List<TestModel>(); Random r = new Random(); int loopTimes = 60000; for (int i = 0; i < loopTimes; i++) { list.Add(new TestModel() { UserID = r.Next(0, loopTimes), BookID = i.ToString() }); } return list; } /// <summary> /// 测试实体 /// </summary> public class TestModel { /// <summary> /// 用户ID /// </summary> public int UserID { get; set; } /// <summary> /// 书ID /// </summary> public string BookID { get; set; } } }