自己封装的内存缓存类DotNet.Caches.Bytecached
Bytecached类是DSS.NET(Distributed State Service分布式状态服务)、DFS.NET(Distributed File System分布式文件系统)中的一个核心内存缓存类。
在DSS.NET中用于保存和管理网站用户的Session数据。
在DFS.NET中用于缓存使用频率较高的文件数据。
特性:
1、使用读写锁实现多线程并发控制
2、多种过期数据清理方式
3、精准的容量控制
4、以最小的系统开销进行数据清理
在一个对性能要求比较高的系统中,都需要用缓存来保存一临时数据。也许你正在寻找。。。
View Code
1 using System; 2 using System.Collections.Generic; 3 using System.Collections.ObjectModel; 4 using System.ComponentModel; 5 using System.Diagnostics; 6 using System.Linq; 7 using System.Threading; 8 using DotNet.Utilities; 9 10 namespace DotNet.Caches 11 { 12 public class Bytecached : IDisposable 13 { 14 private readonly IDictionary<string, byte[]> _caches; 15 private readonly IDictionary<string, DateTime> _times; 16 private long _size; 17 private readonly ReaderWriterLock _readerWriterLock; 18 private readonly BackgroundWorker _checkWorker; 19 20 /// <summary> 21 /// 最大容量/B 22 /// </summary> 23 public long MaxSize { get; set; } 24 25 /// <summary> 26 /// 是否启用缓存 27 /// </summary> 28 public bool Enabled { get; set; } 29 30 /// <summary> 31 /// 超时时间 32 /// </summary> 33 public TimeSpan Timeout { get; set; } 34 35 /// <summary> 36 /// 一次清理数量 37 /// </summary> 38 public int ClearCount { get; set; } 39 40 /// <summary> 41 /// 是否正在检查并清理超时缓存 42 /// </summary> 43 public bool Checking { get; private set; } 44 45 /// <summary> 46 /// 构造 47 /// </summary> 48 /// <param name="timingcheck">定时检查时间</param> 49 public Bytecached(TimeSpan timingcheck = default(TimeSpan)) 50 { 51 _caches = new Dictionary<string, byte[]>(); 52 _times = new Dictionary<string, DateTime>(); 53 _readerWriterLock = new ReaderWriterLock(); 54 MaxSize = 64*1024*1024; 55 Enabled = true; 56 ClearCount = 1; 57 58 #region 检查并清理缓存 59 60 if (timingcheck == default(TimeSpan)) 61 { 62 _checkWorker = new BackgroundWorker(); 63 _checkWorker.DoWork += CheckWorker_DoWork; 64 } 65 else 66 { 67 new Thread(obj => 68 { 69 while (true) 70 { 71 var swt = new Stopwatch(); 72 swt.Start(); 73 CheckWorker_DoWork(null, null); 74 swt.Stop(); 75 Thread.Sleep(timingcheck); 76 } 77 }) { IsBackground = true }.Start(); 78 } 79 80 #endregion 81 } 82 83 public bool Set(string key, byte[] value) 84 { 85 return Set(key, value, DateTime.Now.Add(Timeout)); 86 } 87 88 public bool Set(string key, byte[] value, DateTime effectiveDate) 89 { 90 if (!Enabled) 91 return false; 92 93 _readerWriterLock.AcquireWriterLock(-1); 94 try 95 { 96 if (_caches.ContainsKey(key)) 97 { 98 _size -= _caches[key].Length; 99 _caches[key] = value; 100 _times[key] = effectiveDate; 101 } 102 else 103 { 104 _caches.Add(key, value); 105 _times.Add(key, effectiveDate); 106 } 107 _size += value.Length; 108 } 109 catch(Exception er) 110 { 111 LogUtil.WriteLog("Bytecached.Set", er); 112 return false; 113 } 114 finally 115 { 116 _readerWriterLock.ReleaseWriterLock(); 117 } 118 119 #region 检查并清理缓存 120 121 try 122 { 123 if (_checkWorker != null && !_checkWorker.IsBusy) 124 { 125 _checkWorker.RunWorkerAsync(); 126 } 127 } 128 catch (Exception er) 129 { 130 LogUtil.WriteLog("检查并清理缓存", er); 131 } 132 133 #endregion 134 135 return true; 136 } 137 138 public byte[] Get(string key) 139 { 140 var expiry = Timeout == TimeSpan.Zero ? default(DateTime) : DateTime.Now.Add(Timeout); 141 return Get(key, expiry); 142 } 143 144 public byte[] Get(string key, DateTime effectiveDate) 145 { 146 if (!Enabled) 147 return null; 148 149 _readerWriterLock.AcquireReaderLock(-1); 150 var exist = false; 151 try 152 { 153 byte[] v; 154 exist = _caches.TryGetValue(key, out v); 155 return v; 156 } 157 catch(Exception er) 158 { 159 LogUtil.WriteLog("Bytecached.Get", er); 160 return null; 161 } 162 finally 163 { 164 _readerWriterLock.ReleaseReaderLock(); 165 if (exist && effectiveDate != default(DateTime)) 166 { 167 #region 刷新缓存 168 169 new Thread(obj => 170 { 171 var k = (string)((object[])obj)[0]; 172 var edate = (DateTime)((object[])obj)[1]; 173 while (!Refresh(k, edate)) 174 { 175 Thread.Sleep(100); 176 } 177 }) { IsBackground = true }.Start(new object[]{key, effectiveDate}); 178 179 #endregion 180 } 181 } 182 } 183 184 public bool ContainsKey(string key) 185 { 186 if (!Enabled) 187 return false; 188 189 _readerWriterLock.AcquireReaderLock(-1); 190 try 191 { 192 return _caches.ContainsKey(key); 193 } 194 catch(Exception er) 195 { 196 LogUtil.WriteLog("Bytecached.ContainsKey", er); 197 return false; 198 } 199 finally 200 { 201 _readerWriterLock.ReleaseReaderLock(); 202 } 203 } 204 205 public bool Refresh(string key) 206 { 207 return Timeout != TimeSpan.Zero && Refresh(key, DateTime.Now.Add(Timeout)); 208 } 209 210 public bool Refresh(string key, DateTime effectiveDate) 211 { 212 _readerWriterLock.AcquireWriterLock(-1); 213 try 214 { 215 if (_caches.ContainsKey(key)) 216 { 217 _times[key] = effectiveDate; 218 } 219 } 220 catch(Exception er) 221 { 222 LogUtil.WriteLog("Bytecached.Refresh", er); 223 return false; 224 } 225 finally 226 { 227 _readerWriterLock.ReleaseWriterLock(); 228 } 229 return true; 230 } 231 232 public IList<string> Keys 233 { 234 get 235 { 236 _readerWriterLock.AcquireReaderLock(-1); 237 try 238 { 239 return _caches.Keys.ToList(); 240 } 241 catch (Exception er) 242 { 243 LogUtil.WriteLog("Bytecached.Keys", er); 244 return new List<string>(); 245 } 246 finally 247 { 248 _readerWriterLock.ReleaseReaderLock(); 249 } 250 } 251 } 252 253 public ICollection<byte[]> Values 254 { 255 get 256 { 257 _readerWriterLock.AcquireReaderLock(-1); 258 try 259 { 260 return _caches.Values; 261 } 262 catch (Exception er) 263 { 264 LogUtil.WriteLog("Bytecached.Keys", er); 265 return new List<byte[]>(); 266 } 267 finally 268 { 269 _readerWriterLock.ReleaseReaderLock(); 270 } 271 } 272 } 273 274 public ICollection<DateTime> Times 275 { 276 get 277 { 278 _readerWriterLock.AcquireReaderLock(-1); 279 try 280 { 281 return _times.Values; 282 } 283 catch (Exception er) 284 { 285 LogUtil.WriteLog("Bytecached.Times", er); 286 return new Collection<DateTime>(); 287 } 288 finally 289 { 290 _readerWriterLock.ReleaseReaderLock(); 291 } 292 } 293 } 294 295 /// <summary> 296 /// 移除指定数据 297 /// </summary> 298 /// <param name="key"></param> 299 /// <returns></returns> 300 public bool Remove(string key) 301 { 302 _readerWriterLock.AcquireWriterLock(-1); 303 try 304 { 305 if (_caches.ContainsKey(key)) 306 { 307 _size -= _caches[key].Length; 308 _caches.Remove(key); 309 _times.Remove(key); 310 } 311 } 312 catch(Exception er) 313 { 314 LogUtil.WriteLog("Bytecached.Remove_key", er); 315 return false; 316 } 317 finally 318 { 319 _readerWriterLock.ReleaseWriterLock(); 320 } 321 return true; 322 } 323 324 public void Clear() 325 { 326 _readerWriterLock.AcquireWriterLock(-1); 327 try 328 { 329 _size = 0; 330 _caches.Clear(); 331 _times.Clear(); 332 } 333 catch(Exception er) 334 { 335 LogUtil.WriteLog("Bytecached.Clear", er); 336 } 337 finally 338 { 339 _readerWriterLock.ReleaseWriterLock(); 340 } 341 } 342 343 private void CheckWorker_DoWork(object sender, DoWorkEventArgs e) 344 { 345 Checking = true; 346 try 347 { 348 bool clearSize; 349 bool collect; 350 IEnumerable<string> clearKeys; 351 var count = 0; 352 var swt = new Stopwatch(); 353 var t = new Stopwatch(); 354 355 #region 清理超时记录 356 357 _readerWriterLock.AcquireReaderLock(-1); 358 swt.Start(); 359 try 360 { 361 clearKeys = from time in _times where time.Value <= DateTime.Now orderby time.Value select time.Key; 362 } 363 finally 364 { 365 _readerWriterLock.ReleaseReaderLock(); 366 swt.Stop(); 367 } 368 Thread.Sleep(10); 369 _readerWriterLock.AcquireWriterLock(-1); 370 t.Start(); 371 swt.Reset(); 372 swt.Start(); 373 try 374 { 375 foreach (var clearKey in clearKeys) 376 { 377 if (t.ElapsedMilliseconds > 20) 378 { 379 _readerWriterLock.ReleaseWriterLock(); 380 Thread.Sleep(10); 381 _readerWriterLock.AcquireWriterLock(-1); 382 t.Reset(); 383 } 384 if (_caches.ContainsKey(clearKey)) 385 { 386 _size -= _caches[clearKey].Length; 387 _caches.Remove(clearKey); 388 _times.Remove(clearKey); 389 } 390 count++; 391 } 392 } 393 finally 394 { 395 clearSize = _size >= MaxSize; 396 collect = count > 0 || clearSize; 397 _readerWriterLock.ReleaseWriterLock(); 398 t.Stop(); 399 swt.Stop(); 400 } 401 402 #endregion 403 404 if (clearSize) 405 { 406 #region 清理超量记录 407 408 Thread.Sleep(10); 409 _readerWriterLock.AcquireReaderLock(-1); 410 swt.Reset(); 411 swt.Start(); 412 try 413 { 414 clearKeys = from time in _times orderby time.Value select time.Key; 415 } 416 finally 417 { 418 _readerWriterLock.ReleaseReaderLock(); 419 swt.Stop(); 420 } 421 Thread.Sleep(10); 422 _readerWriterLock.AcquireWriterLock(-1); 423 t.Reset(); 424 t.Start(); 425 swt.Reset(); 426 swt.Start(); 427 count = 0; 428 try 429 { 430 var i = 0; 431 foreach (var clearKey in clearKeys) 432 { 433 if (i == ClearCount - 1) 434 i = 0; 435 if (i == 0 && _size < MaxSize) 436 break; 437 if (t.ElapsedMilliseconds > 20) 438 { 439 _readerWriterLock.ReleaseWriterLock(); 440 Thread.Sleep(10); 441 _readerWriterLock.AcquireWriterLock(-1); 442 t.Reset(); 443 } 444 if (_caches.ContainsKey(clearKey)) 445 { 446 _size -= _caches[clearKey].Length; 447 _caches.Remove(clearKey); 448 _times.Remove(clearKey); 449 } 450 i++; 451 count++; 452 } 453 } 454 finally 455 { 456 _readerWriterLock.ReleaseWriterLock(); 457 t.Stop(); 458 swt.Stop(); 459 } 460 461 #endregion 462 } 463 464 if (collect) 465 { 466 ThreadPool.QueueUserWorkItem(obj => GC.Collect()); 467 } 468 } 469 finally 470 { 471 Checking = false; 472 } 473 } 474 475 public int Count 476 { 477 get 478 { 479 _readerWriterLock.AcquireReaderLock(-1); 480 try 481 { 482 return _caches.Count; 483 } 484 catch(Exception er) 485 { 486 LogUtil.WriteLog("Bytecached.Count", er); 487 return 0; 488 } 489 finally 490 { 491 _readerWriterLock.ReleaseReaderLock(); 492 } 493 } 494 } 495 496 public long Size 497 { 498 get 499 { 500 _readerWriterLock.AcquireReaderLock(-1); 501 try 502 { 503 return _size; 504 } 505 catch (Exception er) 506 { 507 LogUtil.WriteLog("Bytecached.Size", er); 508 return 0; 509 } 510 finally 511 { 512 _readerWriterLock.ReleaseReaderLock(); 513 } 514 } 515 } 516 517 public object[][] List 518 { 519 get 520 { 521 _readerWriterLock.AcquireReaderLock(-1); 522 try 523 { 524 return _caches.Select(obj => new object[] { obj.Key, obj.Value.Length, _times[obj.Key] }).ToArray(); 525 } 526 catch (Exception er) 527 { 528 LogUtil.WriteLog("Bytecached.List", er); 529 return new object[3][]; 530 } 531 finally 532 { 533 _readerWriterLock.ReleaseReaderLock(); 534 } 535 } 536 } 537 538 public void Dispose() 539 { 540 Clear(); 541 } 542 } 543 }