异步和等待-处理对同一方法的多次调用-互相锁定/等待吗?

我有一个复杂的基于任务/锁的混乱局面,无法执行“长”数据操作,而我正在尝试将其替换为异步/等待状态。我是异步的新手,所以我担心自己犯了一些大错误。

为简化起见,我的UI中有一些页面依赖于相同的数据。现在,我只需要获取一次此数据。因此,我对其进行了缓存,并且进一步的调用只是从缓存“ CachedDataObjects”中获取它,而不是每次都进行长时间调用。

像这样(半伪代码):

    private Dictionary<Guid,List<Data>> CachedDataObjects;

    public async Task<List<Data>> GetData(Guid ID)
    {
        List<Data> data = null;

        //see if we have any cached
        CachedDataObjects.TryGetValue(ID, out data);

        if (data == null)
        {
            if (ConnectedToServer)
            {
                data = new List<Data>();
                await Task.Run(() =>
                {
                    try
                    {
                        //long data call
                        data = Service.GetKPI(ID);
                    }
                    catch (Exception e)
                    {
                        //deal with errors (passes an action to do if resolved)
                        PromptForConnection(new Task(async () => { data = await GetData(ID); }), e);
                    }
                });
            }

            CachedDataObjects.Add(ID, data);
        }
        return data;
    }

但是,由于异步调用的性质,两个页面在被触发时会调用此方法。

因此,有一个例外-具有ID的项目已添加到字典中。即使我已解决该问题,但根本的问题仍然存在。数据对象将是不同的版本,我正在做两个网络调用,而我应该只有一个,等等。

以前,我通过将整个方法封装在lock语句中来“破解”一个解决方案-从而仅允许对其进行一次调用。我所有的数据加载都是在后台工作人员中完成的,第一个完成了调用,一旦完成,其他人便被解锁以执行快速抓取。

但是我不能在异步方法中使用锁,而且该解决方案还是感觉不好。

异步方法是否可以“等待”其他异步调用完成?

斯蒂芬·克莱里(Stephen Cleary)

您的问题是在await将任务添加到字典之前先完成任务。在这种情况下,您需要将任务添加到词典中,以便调用此方法的下一页将获得相同的任务:

public Task<List<Data>> GetData(Guid ID)
{
  Task<List<Data>> task = null;
  CachedDataObjects.TryGetValue(ID, out task);
  if (task == null)
  {
    if (ConnectedToServer)
    {
      task = Task.Run(() =>
      {
        try
        {
          //long data call
          return Service.GetKPI(ID);
        }
        catch (Exception e)
        {
          //deal with errors
        }
      });
    }
    DataObjects.Add(ID, task);
  }
  return task;
}

这将缓存任务但是,如果//deal with errors传播异常,则这也会缓存该异常。

为了避免这种情况,您可以使用更复杂的代码,也可以采用我的AsyncLazy<T>类型

private readonly ConcurrentDictionary<Guid, AsyncLazy<List<Data>>> CachedDataObjects;
public Task<List<Data>> GetData(Guid ID)
{
  var lazy = CachedDataObjects.GetOrAdd(ID, id =>
      new AsyncLazy<List<Data>>(() => Task.Run(() =>
      {
        try
        {
          return Service.GetKPI(ID);
        }
        catch (Exception e)
        {
          //deal with errors
          throw;
        }
      }, AsyncLazyFlags.RetryOnFailure | AsyncLazyFlags.ExecuteOnCallingThread)));
  return lazy.Task;
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

异步和等待调用者不是异步但被调用的方法是

来自分类Dev

在C#5中多次异步调用同一方法是否安全?

来自分类Dev

在异步/等待中调用异步方法和TaskScheduler

来自分类Dev

MVVMCross异步和等待方法在PCL中

来自分类Dev

在同一方法中使用多个等待的效果?

来自分类Dev

异步/等待:使方法异步

来自分类Dev

使用 Xamarin MessagingCenter 调用异步方法时如何处理异步和等待?

来自分类Dev

单一方法中的多个等待

来自分类Dev

单一方法中的多个等待

来自分类Dev

异步和等待与循环

来自分类Dev

异步/等待和递归

来自分类Dev

无尽的异步和等待?

来自分类Dev

异步等待和并行

来自分类Dev

异步等待和线程

来自分类Dev

异步和等待

来自分类Dev

如何使用默认覆盖的异步处理和等待

来自分类Dev

如何使用异步和等待正确处理

来自分类Dev

使用异步和等待处理查询

来自分类Dev

WCF 4.5和异常处理中的C#异步等待

来自分类Dev

如何使用默认覆盖的异步处理和等待

来自分类Dev

等待深度异步等待深度函数调用的结果吗?

来自分类Dev

异步方法中返回和等待任务之间的区别

来自分类Dev

等待异步任务安全和有效的方法

来自分类Dev

异步方法中返回和等待任务之间的区别

来自分类Dev

异步和等待如何替代现有方法?

来自分类Dev

取消C#中的异步和等待方法

来自分类Dev

异步等待调用长时间运行的同步和异步方法

来自分类Dev

等待非异步方法

来自分类Dev

异步方法等待结束?