.net 如何支持多线程异步锁定。。。可能是分布式锁定
我的问题涉及到在多线程异步系统中保护关键资源。它是一个用Asp.NETMVC、WebApi以及托管在IIS中的WCF项目编写的web应用程序。关键区域是缓存(目前是内存中的System.Runtime.MemoryCache…但请参见下文,也可以是分布式AppFabric/Reddis缓存) 背景域 我在医疗保健部门工作,我们收集患者信息,例如他们的文档列表(如转录本、报告)、遭遇事件(如入院)和实验室(如血液检测)。我们有一个PatientChart对象跟踪所有这些数据(例如,所有文档的ID+标题,但不是实际内容) 我们系统中的工作流示例.net 如何支持多线程异步锁定。。。可能是分布式锁定,.net,multithreading,asynchronous,locking,.net,Multithreading,Asynchronous,Locking,我的问题涉及到在多线程异步系统中保护关键资源。它是一个用Asp.NETMVC、WebApi以及托管在IIS中的WCF项目编写的web应用程序。关键区域是缓存(目前是内存中的System.Runtime.MemoryCache…但请参见下文,也可以是分布式AppFabric/Reddis缓存) 背景域 我在医疗保健部门工作,我们收集患者信息,例如他们的文档列表(如转录本、报告)、遭遇事件(如入院)和实验室(如血液检测)。我们有一个PatientChart对象跟踪所有这些数据(例如,所有文档的ID+
- 用户选择患者
- 请求预取所有基础数据
- 启动后台线程/任务以异步完成工作
- 单个数据与“PatientChart”一样存储在缓存中 反对
public class PatientProcessorService
{
private static readonly SemaphoreSlim _semaphoreSlim = new SemaphoreSlim(initialCount: 1);
// this method called asynchronously via multiple parallel threads, based on a master list of document Ids
private async Task<Document> GetDocument(string patientId, int documentId)
{
Document document = _documentService.Get(patientId, documentId);
await _cacheService.Set(documentCacheKey, document);
PatientChart patientChart = null;
await _semaphoreSlim.WaitAsync();
try
{
patientChart = await _cacheService.Get(cacheKey) as PatientChart;
if (patientChart != null)
{
// update the patient chart with whatever new data/information we have
patientChart.Message = "Document + " documentId + " retrieved";
patientChart.LastUpdated = DateTime.Now;
patientChart.Documents.Add(new DocumentMetaInfo() {
Id=documentId,
Title=document.Title,
CacheKeyLocation=documentCacheKey});
await _cacheService.Set(cacheKey, patientChart);
}
}
finally {
_semaphoreSlim.Release();
}
}
}
公共类PatientProcessorService
{
private static readonly SemaphoreSlim _SemaphoreSlim=新的SemaphoreSlim(initialCount:1);
//此方法基于文档ID的主列表,通过多个并行线程异步调用
私有异步任务GetDocument(字符串patientId,int documentId)
{
documentdocument=\u documentService.Get(patientId,documentId);
wait_cacheService.Set(documentCacheKey,document);
PatientChart PatientChart=null;
wait_semaphoreSlim.WaitAsync();
尝试
{
patientChart=wait_cacheService.Get(cacheKey)作为patientChart;
if(patientChart!=null)
{
//使用我们掌握的任何新数据/信息更新病历
patientChart.Message=“文档+”文档ID+“已检索”;
patientChart.LastUpdated=DateTime.Now;
patientChart.Documents.Add(新的DocumentMetaInfo(){
Id=documentId,
Title=document.Title,
CacheKeyLocation=documentCacheKey});
wait_cacheService.Set(cacheKey,patientChart);
}
}
最后{
_semaphoreSlim.Release();
}
}
}
一些问题
1) 上述说法有意义吗?有什么明显的问题吗
2) 今天,上面的代码只是一个原型,用来证明各种事情。但是,如果我们计划推出这种体系结构,我们很可能不得不转向分布式缓存(如AppFabric、Redis),并引入持久队列(如MSMQ、RabbitMQ)和windows服务(与IIS中的后台任务/线程相反),以提供负载平衡和可扩展性
在这种情况下,我假设我的锁必须实现得更低(因为我可能有不同的进程访问缓存)。e、 g.如果我使用AppFabric,我是否必须使用GetAndLock和PutAndUnlock api,加上Guy Godin编写的支持“块+等待”逻辑(通过异常、重试和超时逻辑)的扩展
我相信它模仿了Redis的实现:
更新后的代码可能是这样的
public class PatientProcessorService
{
// this method called asynchronously via multiple parallel threads, based on a master list of document Ids
private async Task<Document> GetDocument(string patientId, int documentId)
{
Document document = _documentService.Get(patientId, documentId);
myAppFabricCache.Set(documentCacheKey, document);
PatientChart patientChart = null;
// e.g. using appfabric DataCache and extension from Guy Godin in above link
using (myAppFabricCache.AquireLock(cacheKey, timeOut)
{
patientChart = myAppFabricCache.Get(cacheKey) as PatientChart;
if (patientChart != null)
{
// update the patient chart with whatever new data/information we have
patientChart.Message = "Document + " documentId + " retrieved";
patientChart.LastUpdated = DateTime.Now;
patientChart.Documents.Add(new DocumentMetaInfo() {
Id=documentId,
Title=document.Title,
CacheKeyLocation=documentCacheKey});
}
myAppFabricCache.Set(cacheKey, patientChart);
}
}
}
公共类PatientProcessorService
{
//此方法基于文档ID的主列表,通过多个并行线程异步调用
私有异步任务GetDocument(字符串patientId,int documentId)
{
documentdocument=\u documentService.Get(patientId,documentId);
myAppFabricCache.Set(documentCacheKey,document);
PatientChart PatientChart=null;
//例如,在上述链接中使用来自Guy Godin的appfabric数据缓存和扩展
使用(myAppFabricCache.AquireLock)(缓存键,超时)
{
patientChart=myAppFabricCache.Get(cacheKey)作为patientChart;
if(patientChart!=null)
{
//使用我们掌握的任何新数据/信息更新病历
patientChart.Message=“文档+”文档ID+“已检索”;
patientChart.LastUpdated=DateTime.Now;
patientChart.Documents.Add(新的DocumentMetaInfo(){
Id=documentId,
Title=document.Title,
CacheKeyLocation=documentCacheKey});
}
设置(cacheKey,patientChart);
}
}
}
3) 上面的问题是,我甚至不知道如何重构代码,使其与cahce实现无关。。。因此,关于如何做到这一切的建议将不胜感激
谢谢你读到这里 patientChart的一生是什么。从高层次的角度来看,patientChart是患者的“记录簿”吗?是的,它就像一本记录簿。设想一下,它也将用于登录页/仪表板类型的视图中。生命周期将取决于微调-保存在缓存中,例如15分钟,或者可能一天…您谈论的是持久队列和分布式缓存。我忍不住想,这可能是利用NServiceBus作为队列上的流程管理器,并利用SOA来拆分域/上下文的候选方案。我甚至会考虑删除CQRS——尤其是如果你读的比你写的多,而且你打算扩大你的阅读方面。