使用异步/等待 - C# [关闭]
Posted
技术标签:
【中文标题】使用异步/等待 - C# [关闭]【英文标题】:using async/await - c# [closed] 【发布时间】:2021-12-20 20:40:29 【问题描述】:我有以下代码。代码究竟做了什么?为什么我们需要Stopwatch
、XmlSerializer
、MemoryStream
。使用async/await
是否有更简单的方法?
使用contentResponse.Result;
也会导致死锁情况。
public T GetResponse<T>()
var response = default(T);
using (HttpClient httpClient = new HttpClient())
httpClient.DefaultRequestHeaders.Add("Authorization", authHeader);
Stopwatch watch = Stopwatch.StartNew();
var contentResponse = httpClient.GetAsync(uri.ToString());
try
contentResponse.Wait();
catch (Exception exception)
var wsResponseContent = contentResponse.Result;
wsResponseContent.Content.LoadIntoBufferAsync();
var resultTask = wsResponseContent.Content.ReadAsStringAsync();
resultTask.Wait();
string wsResponseContentText = resultTask.Result;
if (watch.IsRunning)
watch.Stop();
wsResponseContent.EnsureSuccessStatusCode();
if (wsResponseContent.IsSuccessStatusCode)
XmlSerializer result = new XmlSerializer(typeof(T));
using (MemoryStream sresultStream = new MemoryStream(Encoding.UTF8.GetBytes(wsResponseContentText)))
response = (T)result.Deserialize(sresultStream);
sresultStream.Close();
return response;
【问题讨论】:
这段代码在很多方面都很糟糕,需要很长时间才能回答。从阅读开始:***.com/a/69859015/2141621 至于秒表——我看不到它在任何地方都被使用过,所以它几乎和它不存在一样——除了它增加了复杂性。 好吧,秒表确实被创建、启动和停止了。所有有用的操作,如果你最终要读取它的值(不像这里,它被忽略了)。摆脱它 @JonasH 绝对不可能,“代码到底是做什么的?”代码审查不解释代码。 通常秒表有两种使用方式,要么对操作进行基准测试(“这需要多长时间” - 在这种情况下,它会在升级到生产之前被删除)或记录(同样需要多长时间这样做了)。在这种情况下,watch
的范围在 using
块内。它被创建、启动和停止,但从不读取。它与并行处理没有有关。这里的唯一目的是测量StartNew
和Stop
之间经过的时间
【参考方案1】:
此代码中不需要秒表。通常用作诊断工具,它可能很有用。但在这种情况下不是。
从下面的代码看来,它读取了通过网络发送的字符串并尝试将其读取为 XML 格式。因此需要MemoryStream
和XMLSerializer
。
至于你的僵局情况。这总是因为两个实例试图访问同一个实例。您可以通过正确地等待您的功能来避免这种情况。
如果oyu真的想要一个合适的async
,实现如下功能:
public async Task<T> GetResponse<T>()
var response = default(T);
using (HttpClient httpClient = new HttpClient())
httpClient.DefaultRequestHeaders.Add("Authorization", authHeader);
var contentResponse = await httpClient.GetAsync(uri.ToString());
await wsResponseContent.Content.LoadIntoBufferAsync();
var wsResponseContentText = await wsResponseContent.Content.ReadAsStringAsync();
wsResponseContent.EnsureSuccessStatusCode();
if (wsResponseContent.IsSuccessStatusCode)
XmlSerializer result = new XmlSerializer(typeof(T));
using (MemoryStream sresultStream = new MemoryStream(Encoding.UTF8.GetBytes(wsResponseContentText)))
response = (T)result.Deserialize(sresultStream);
sresultStream.Close();
return response;
在上面的代码中,如果一个函数中有async
。我们可以等待结果而不是任务。比如下面的代码:
public async Task<int> GetNumber5Async()
return 5;
如果我们像你以前那样称呼它:
var number5 = GetNumber5Async(); // Returns Task<int>
我们将收到一个我们需要从中获取结果的任务。但是,如果我们立即等待任务:
var number5 = await GetNumber5Async(); // Returns 5
我们会立即返回结果,无需执行number5.Wait(); number5.result;
乌龟一路向下
使用异步方法时您需要了解的一件事是“Turtes all way Down”的概念。 简单地说,如果您在任何地方都有异步方法,那么您的所有方法都会调用它,并且调用这些方法也需要是异步的。 那么异步方法需要什么?
-
In 需要是
Task
。因此,它需要返回一个封装了值的Task
,而不是返回一个值。
例如:
// None Async
public int GetNumber5() return 5;
// Async
public async Task<int> GetNumber5Async() return 5;
-
需要
async
描述符才能使用和调用await
函数。
例如:
// None Async
void GetANumber()
var num5 = GetNumber5();
// Async
async void GetANumber()
var num5 = await GetNumber5Async();
使用异步避免死锁
通常等待一个函数就足够了。但如果它仍然会产生死锁,您可以添加 '.ConfigureAwait(false);'
例如:
var num5 = await GetNumber5Async().ConfigureAwait(false);
【讨论】:
啊,别人用“Turtles all way Down”来描述async/await编码 Stephen Cleary 的粗略规则:如果您正在编写库代码,请使用ConfigureAwait(false)
,如果您不是,请不要到目前为止对我有用以上是关于使用异步/等待 - C# [关闭]的主要内容,如果未能解决你的问题,请参考以下文章