问题描述
我有一个 ASP.NET 控制器,它在内部调用 API 和缓存以获取答案,并从完成的第一个任务中返回答案。一般来说,API比缓存慢很多,缓存在50ms内返回,而API在第95个百分位2秒内返回。
要求:
- 如果可用,立即从缓存中返回答案。否则等待 API 并返回可用/空响应(视情况而定)。
- API 调用完成后,我们会使用新答案更新缓存(如果有)。
问题: 如何在不阻塞控制器的情况下等待 API 调用并在后台线程中写入缓存?
当前流量:
Task<string>[] getDataTasks = new Task<string>[]
{
getDataFromAPI(),getDataFromCache()
};
var finishedTaskIndex = Task.WaitAny(getDataTasks);
var response = getDataTasks[finishedTaskIndex].Result;
if (finishedTaskIndex == 1 && string.IsNullOrEmpty(response))
{
response = await getDataTasks[0];
writetoCacheTask(response); //fire and forget,this is non-blocking
}
**//Problem :- How to await for response from API and write to cache in a non-blocking manner** THIS DOES NOT WORK
Task.Run(async () =>
{
var apiResponse = await getDataTasks[0];
writetoCacheTask(apiResponse);
});
return response;
在上面,即使我使用一个新线程来等待独立于主线程的api调用,它也不起作用。
不起作用 尝试在任务上使用 ContinueWith 并带有 TaskContinuationoptions = ExecuteSynchronously 的回调,因为这会在调用任务的同一线程上继续。但我可能理解错了。
Task.Run(async () =>
{
return await getDataTasks[0];
}).ContinueWith(this.CallBack,TaskContinuationoptions.ExecuteSynchronously);
有效:使用委托处理程序
// private members of controller
private delegate string DelegateHandler();
private string getDataFromAPisync()
{
return getDataFromAPI().GetAwaiter().GetResults();
}
private string getDataFromCacheSync()
{
return getDataFromCache().GetAwaiter().GetResults();
}
private void CallBack(IAsyncResult ar)
{
var apiResponse = apiInvoker.EndInvoke(ar);
writetoCacheTask(apiResponse);
}
// In controller
var apiInvoker = new DelegateHandler(this.getDataFromAPisync)
var cacheInvoker = new DelegateHandler(this.getDataFromCacheSync)
IAsyncResult apiResults = apiInvoker.BeginInvoke(this.CallBack,null);
IAsyncResult cacheResults = cacheInvoker.BeginInvoke(null,null);
var handles = new WaitHandle[]
{
apiResults.AsyncWaitHandle,cacheResults.AsyncWaitHandle
}
WaitHandle.WaitAny(handles);
if (cacheResults.IsCompleted)
{
return cacheInvoker.EndInvoke(ar);
}
return apiInvoker.EndInvoke(ar);
当我使用委托处理程序时,它看起来像用于进行 api 调用的后台线程,也用于处理回调,并且只有在回调完成后它才会被终止。
如何使用任务库做同样的事情?
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)