You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#接口请求代码功能及Stopwatch、async/await用法与死锁问题咨询

代码功能说明

这段是C#的泛型工具方法,实现的逻辑是:

  • 新建HttpClient实例,添加Authorization请求头,向指定URI发起HTTP GET请求
  • 全程统计请求耗时,拿到响应后读取响应内容为字符串
  • 校验响应状态码为成功的前提下,将XML格式的响应内容反序列化为指定的泛型类型T实例后返回
    注意原代码存在空吞异常、每次新建HttpClient易引发端口耗尽、同步阻塞异步方法易引发死锁等问题。
核心类作用说明
  • Stopwatch:.NET提供的高精度计时器,这里用来统计从发起HTTP请求到读取完响应内容的全链路耗时,可用于性能监控、接口耗时统计等场景。
  • XmlSerializer:.NET内置的XML序列化/反序列化组件,这里的作用是将接口返回的XML格式字符串,转换为开发者指定的泛型类型T的强类型实体对象,无需手动解析XML节点。
  • MemoryStream:基于内存的流实现,因为XmlSerializer的反序列化方法只接收流类型入参,这里是将XML字符串转成UTF8字节数组后封装为内存流,不需要写磁盘,性能更高,用完会自动释放。
async/await 优化实现

完全可以用async/await改写,改写后既能避免同步阻塞问题,代码也更简洁易读,优化后代码如下:

// 异步方法约定返回Task<T>,方法名加Async后缀
public async Task<T> GetResponseAsync<T>()
{
    var response = default(T);
    // 注意:生产环境建议复用HttpClient实例或通过IHttpClientFactory注入,避免端口耗尽问题
    using (HttpClient httpClient = new HttpClient())
    {
        httpClient.DefaultRequestHeaders.Add("Authorization", authHeader);
        Stopwatch watch = Stopwatch.StartNew();
        
        // 用await代替Wait()和Result,无需手动阻塞线程
        var wsResponseContent = await httpClient.GetAsync(uri.ToString());
        await wsResponseContent.Content.LoadIntoBufferAsync();
        string wsResponseContentText = await wsResponseContent.Content.ReadAsStringAsync();
        
        if (watch.IsRunning)
            watch.Stop();
            
        wsResponseContent.EnsureSuccessStatusCode();
        if (wsResponseContent.IsSuccessStatusCode)
        {
            XmlSerializer serializer = new XmlSerializer(typeof(T));
            using (MemoryStream sresultStream = new MemoryStream(Encoding.UTF8.GetBytes(wsResponseContentText)))
            {
                response = (T)serializer.Deserialize(sresultStream);
                // using语句会自动释放流,无需手动调用Close()
            }
        }
    }
    return response;
}
关于contentResponse.Result死锁的问题

调用contentResponse.Result并不一定会导致死锁,死锁的发生需要满足两个前提:

  1. 当前运行环境存在同步上下文(SynchronizationContext),比如WinForm/WPF的UI线程、http://ASP.NET Framework的请求处理线程都自带同步上下文;
  2. 调用.Result/.Wait()的线程阻塞了同步上下文,而异步方法执行完成后需要回到原同步上下文执行后续逻辑,两者互相等待就会触发死锁。
    如果是在没有同步上下文的环境,比如控制台程序、http://ASP.NET Core应用中,默认没有同步上下文,调用.Result通常不会死锁,但仍然不推荐这种写法:同步阻塞会浪费线程资源,高并发场景下容易引发线程池饥饿,导致服务吞吐量下降。

内容的提问来源于stack exchange,提问作者user2281858

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 08:24:01