gpt4 book ai didi

c# - 异步/等待指导 : Intrinsic Signature Proliferation

转载 作者:太空狗 更新时间:2023-10-30 00:24:21 25 4
gpt4 key购买 nike

考虑以下负责使用 .NET HttpClient 与 API 通信的类。

public class ApiServiceAgent
{
public async Task<string> GetItem()
{
var client = new HttpClient();
var uri = new Uri("http://stackoverflow.com");
var response = await client.GetAsync(uri);
return await response.Content.ReadAsStringAsync();
}
}

虽然经过简化,但它代表了我编写与 HTTP API 通信的代码的方式。

现在考虑我希望在我自己的 Web API 项目中使用这个类。为简单起见,假设我有两个额外的类(直接或以其他方式)调用此类。

  • 存储库 - 负责调用我的服务代理、读取结果并返回某种形式的领域对象。
  • Controller - 一个 ASP.NET Web API Controller - 我的 API 的入口点,负责将数据返回给调用 API 的用户。

这两个类可能如下所示:

public class Controller : ApiController
{
public async Task<string> Get()
{
var repository = new Repository();
return await repository.GetItem();
}
}

public class Repository
{
public async Task<string> GetItem()
{
var serviceAgent = new ApiServiceAgent();
var apiResponse = await serviceAgent.GetItem();
//For simplicity/brevity my domain object is a lowercase string
return apiResponse.ToLower();
}
}

在上面的两个类中,async/Task 方法签名本质上一直传播到 Controller...这在您看到的关于 async/await 主题的大多数示例 .NET 代码中很常见。

然而,在您目前看到的大多数 async/await“最佳实践”文章/视频中,都强调 async/await 应该用于真正的异步操作.

我会争辩说,无论是 Repository 还是 Controller 都不会做任何真正异步的事情——这些都是在 Service Agent 中完成的。

我是否应该阻止 async/await 在我的代码中变得如此多产?

以下是否更能代表“最佳实践”异步/等待?

public class Controller : ApiController
{
public string Get()
{
var repository = new Repository();
return repository.GetItem();
}
}

public class Repository
{
public string GetItem()
{
var serviceAgent = new ApiServiceAgent();
var apiResponseTask = serviceAgent.GetItem();
var apiResponse = apiResponse.GetAwaiter().GetResult();
return apiResponse.ToLower();
}
}

我是不是太离谱了?如果是这样...请给我指出正确的方向。

最佳答案

我认为那些方法异步的——但只是因为 API 部分。这种异步只会向上传播。

您对 Repository.GetItem() 的第二次实现有问题,海事组织:

  • 您不应该调用服务员的GetResult()等待者完成之前的方法。事实上,在我看来,唯一在您自己的代码中直接使用 awaiter 的情况是在您实现自己的 awaiter 时。 (而且这种情况应该很少见。)在这种情况下,我认为与使用 Task<T>.Result 的效果相同。 ,但任务等待者有可能在调用之前验证任务是否已完成(或出错)。
  • 您不应该对 API 响应使用阻塞调用,以将异步 API 转变为同步 API 而无需特别小心。根据代码的确切性质,它很容易导致死锁......如果在单线程同步上下文中进行阻塞调用并且异步操作需要返回到相同的同步上下文,你将结束编写等待任务完成的代码,以及等待线程可用的任务。

这表明您的方法应该有一个 Async顺便说一下,后缀 - 但这并不意味着它们必须是 async方法。第二个可能是,但第一个可以简单地写成:

public class Controller : ApiController
{
public Task<string> GetAsync()
{
var repository = new Repository();
return repository.GetItemAsync();
}
}

制作方法很少有好处 async如果它只有一个 await直接用于返回值。

为您的Repository方法,await会很有用,因为你有代码在完成后运行 - 你可以使用 ContinueWith直接,但那样会更痛苦。所以我将其保留为 async/await版本,只需将其重命名为 GetItemAsync ...并可能使用 ConfigureAwait(false)表明您实际上不需要该方法返回相同的上下文。

关于c# - 异步/等待指导 : Intrinsic Signature Proliferation,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26375313/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com