使用Windows Server AppFabric缓存的分布式锁服务
发布时间:2020-12-14 02:51:38 所属栏目:Windows 来源:网络整理
导读:我有一个在 Windows Server AppFabric SDK中找到的Microsoft.ApplicationServer.Caching.DataCache对象的扩展方法,如下所示: using System;using System.Collections.Generic;using Microsoft.ApplicationServer.Caching;namespace Caching{ public static
我有一个在
Windows Server AppFabric SDK中找到的Microsoft.ApplicationServer.Caching.DataCache对象的扩展方法,如下所示:
using System; using System.Collections.Generic; using Microsoft.ApplicationServer.Caching; namespace Caching { public static class CacheExtensions { private static Dictionary<string,object> locks = new Dictionary<string,object>(); public static T Fetch<T>(this DataCache @this,string key,Func<T> func) { return @this.Fetch(key,func,TimeSpan.FromSeconds(30)); } public static T Fetch<T>(this DataCache @this,Func<T> func,TimeSpan timeout) { var result = @this.Get(key); if (result == null) { lock (GetLock(key)) { result = @this.Get(key); if (result == null) { result = func(); if (result != null) { @this.Put(key,result,timeout); } } } } return (T)result; } private static object GetLock(string key) { object @lock = null; if (!locks.TryGetValue(key,out @lock)) { lock (locks) { if (!locks.TryGetValue(key,out @lock)) { @lock = new object(); locks.Add(key,@lock); } } } return @lock; } } } 目的是让开发人员编写代码,说“先通过尝试缓存来获取一些数据.如果在缓存中不可用,则执行指定的函数,将结果放入缓存中以供下一个调用者使用,然后返回结果”.像这样: var data = dataCache.Fetch("key",() => SomeLongRunningOperation()); 执行潜在长时间运行的函数的锁定限制调用单个线程,但仅限于同一台机器上的单个进程.您将如何扩展此模式以使锁定分布以防止多个进程/机器立即执行该函数? 解决方法
AppFabric拥有自己的分布式锁定机制,您可以通过GetAndLock / PutAndUnlock方法系列访问它.如果您的项目被锁定,正常的Get调用仍将成功并返回最后一个值,但进一步的GetAndLock调用将抛出异常.在您的客户端第一次请求缓存对象的情况下,您仍然可以锁定密钥,即使它尚不存在(它更像是一个预留而不是一个实体锁).
public static T Fetch<T>(this DataCache @this,TimeSpan timeout) { var result = @this.Get(key); if (result == null) ( DataCacheLockHandle handle; // We need a timespan to allow func time to run TimeSpan funcTimespan = New TimeSpan(0,1,0); try { // Lock the key // If something goes wrong here it will unlock at the end of funcTimespan var result = @this.GetAndLock(key,funcTimespan,handle); if (result == null) { // Still no value so go and run func result = func(); @this.PutAndUnlock(key,handle,timeout); } else { // There's a value now so we'll unlock the key and reset it's timeout @this.Unlock(key,timeout); } } catch (DataCacheException ex) { if (ex.ErrorCode == DataCacheErrorCode.ObjectLocked) { // Another process has locked the key so func must be running right now // We'll return null to the client result = null; } } if (result == null) { return null; } else { return (T)result; } ) } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |