将同步缓存机制添加到异步方法“;透明”;

本文关键字:透明 异步方法 同步 缓存 机制 添加 | 更新日期: 2023-09-27 18:27:06

我有一个方法,它使用async task执行长操作
现在,我想添加一个在相同方法中透明的缓存机制。现在,我总是可以获取缓存结果并用Task包装它,这样它就会"工作",但我想阻止我将得到的上下文切换

下面是我的一个例子:

var result = await LongTask();
private async Task<string> LongTask()
{
   return await DoSomethingLong();
}

这里有一个我想要的例子:

var result = await LongTask();
private async Task<string> LongTask()
{
   if(isInCache)
   { 
      return cachedValue(); // cache value is a const string you can do return "1" instead.
   }
   // else do the long thing and return my Task<string>
   return await DoSomethingLong();
}

现在,我很惊讶地看到,这个编译和工作
某些东西告诉我做得不正确。

下面是我测试过的另一个类似的例子:

private async Task<string> DownloadString(bool sync)
{
    using (WebClient wc = new WebClient())
    {
        var task = wc.DownloadStringTaskAsync("http://www.nba.com");
        if(sync)
            return task.Result;
        return await task;
    }
}

这是代码:

var res = DownloadString(true);
string str1 = await res;
var res2 = DownloadString(false);
string str2 = await res2;

根据我在这里读到的内容,task.Result同步执行任务并返回一个string。现在,我通过Fiddler看到了请求,我的程序卡在了return task.Result行,尽管我看到了200 OK,我等待了很长时间。

底线:

  1. 在异步方法中使用缓存的最佳''正确方式是什么(例如,在某些情况下同步执行某些操作而不创建context switch overhead
  2. 为什么我使用DownloadString的第二个代码块被卡住了

将同步缓存机制添加到异步方法“;透明”;

首先,如果在调用async方法后返回的任务已经完成,则不需要上下文切换,因为不需要任何上下文切换。所以这是完全可以接受的:

private async Task<string> LongTask()
{
   if(isInCache)
   { 
      return cachedValue(); // cache value is a const string you can do return "1" instead.
   }
   // else do the long thing and return my Task<string>
   return await DoSomethingLong();
}

但是,在缓存结果的情况下,async机制是多余的。这种开销几乎可以忽略不计,但您可以通过删除asyncawait并使用Task.FromResult:创建一个已完成的任务来提高性能

private Task<string> LongTask()
{
   if(isInCache)
   { 
      return Task.FromResult(cachedValue()); 
   }
   // else do the long thing and return my Task<string>
   return DoSomethingLong();
}

当您编写"wait-someObject;"时,编译器将生成代码来检查someObject表示的操作是否已经完成。如果有,执行将在等待点上同步继续。如果没有,生成的代码将把一个延续委托挂接到等待的对象,这样当所表示的操作完成时,该延续委托将被调用

来自异步/等待常见问题


Task.Result同步执行任务,而是同步等待。这意味着调用线程被阻塞,等待任务完成。当您在具有SynchronizationContext的环境中使用它时,可能会导致死锁,因为线程被阻塞,无法处理任务的完成。您不应该对尚未完成的任务使用Result属性。