为 NCache Get 实现 Awaitable 异步方法

Implementing Awaitable Async method for NCache Get

我们正在将所有或大部分 .NET 4.6 MVC WebAPI 控制器方法重构为 async 方法。

这似乎适用于具有可等待方法的较低级别调用的方法,例如 SQL 命令执行;然而,我们正在使用 Alachisoft 的内存分布式缓存框架,称为 NCache(准确地说是 4.6 SP2),它不提供任何真正的异步方法。

是否值得创建一个 async 辅助方法来公开可等待的 Task<object> return 类型?

传统上使用 NCache API,您 Get 在以下用法中通过 Key 从缓存中获取一个对象;

NCacheObject.Get(string);

建议创建以下辅助方法;

protected static async Task<Object> GetAsync(string key, Cache nCache)
{
    Task<Object> getTask = new Task<Object>(() => nCache.Get(key));
    getTask.Start();
    return await getTask.ConfigureAwait(false);
}

这样它就可以允许 async 方法的完整瀑布,直至入口控制器方法;

public static async Task<Tuple<List<SomeModel>, bool, string>> GetSomeModelList(string apiKey)
{
    return newTuple<List<SomeModel>, bool, string>(await GetAsync("GetSomeModelKey", CacheInstance).ConfigureAwait(false), true, "Success message");
}

最后是控制器方法;

[HttpGet, Route("Route/Method")]
public async Task<ResponseOutputModel<List<SomeModel>>> GetSomeModelList()
{
    ResponseOutputModel<List<SomeModel>> resp = new ResponseOutputModel<List<SomeModel>>();

    try
    {
        Tuple<List<SomeModel>, Boolean, String> asyncResp = await CacheProcessing.GetSomeModelList(GetApiKey()).ConfigureAwait(false);

        resp.Response = asyncResp.Item1;
        resp.Success = asyncResp.Item2;
        resp.Message = asyncResp.Item3;
    }
    catch (Exception ex)
    {
        LoggingHelper.Write(ex);
        resp.StatusCode = Enumerations.ApiResponseStatusCodes.ProcessingError;
        resp.Success = false;
        resp.Message = ex.Message;
    }

    return resp;
}

这会使重构复杂化,因为原始方法实际上具有 bool successstring message 的输出参数;但似乎这可以使用 Tuple<>; 以一种体面和快速的方式完成。否则我们只能创建一个 return 类型的模型。

要正确地做到这一点,需要重构数百种方法;相当艰巨的任务。

  1. 这是否会按预期工作,并且是完成 objective 的最佳解决方案?
  2. 为了提高可扩展性以及随后 "performance" Web 服务器的最终目标,是否值得付出所有的努力?

因为这是一个内存缓存,我说这是出于对 NCache 的任何直接体验,但对其他缓存系统的体验。

  1. 是的,这当然可行。我宁愿选择一个响应结构或一个通用的 class 允许我定义我的响应类型(如果可能的话)。元组还不错,如果你选择 classes 可能会更高效。但它们并不容易上眼。
  2. 现在,谈到性能时,有一个问题。这是给你的缓存服务器,你当然想要快速读写。访问内存缓存应该很容易。由于您在这里直接访问内存,因此从性能的角度来看,它不会给您带来太多好处。您是否确定您的代码是完全异步的并且您正在正确使用线程池来使一切正常?是的,当然可以,但它所做的只是添加一个额外的层或在您访问缓存时工作。
  3. 当你要进行异步时,请确保你的内存缓存是线程安全的。 :)

Would it be worth creating an async helper method that would expose a awaitable Task return type?

Nope.

The proposal is to create a helper method of the following

这只是将内存中的工作排队到线程池。

(旁注:永远不要使用任务构造函数。永远。如果您需要将工作排队到线程池,请使用 Task.Run 而不是 Start 的任务构造函数)

Would this work as expected, and be the best solution to accomplish the objective?

Is it likely worth all of the effort required, with the end goal of increasing scalability and subsequently "performance" of the web servers?

这是同一个问题。 objective 是可扩展性;异步只是帮助您完成它的一种方法。

异步有助于 ASP.NET 的可伸缩性,因为它释放了一个可以处理其他请求的线程。但是,如果您使用另一个线程创建异步方法,那么这对您根本没有帮助。我称之为 "fake asynchrony" - 这些类型的方法 看起来 是异步的,但它们实际上只是同步 运行 在线程池上。

与真正的异步相反,伪异步实际上会损害您的可扩展性。