在macOS上省略async和await的HttpClient未抛出异常问题咨询
为什么省略async/await后没抛出预期的异常?
我来帮你捋清楚这个问题——你写的这段代码确实存在潜在的资源释放风险,但没抛出异常是有具体原因的,咱们一步步拆解:
首先看你的Get方法:
public static Task<string> Get() { using (var http = new HttpClient()) return http.GetStringAsync("http://google.com"); }
按照Stephen Cleary博客里的说法,这里的using会在你返回Task的瞬间就释放HttpClient,但此时GetStringAsync的异步请求可能还没完成,理论上应该触发ObjectDisposedException之类的异常,但你没碰到,主要有这几个原因:
- HttpClient的Dispose逻辑特殊:HttpClient本身的Dispose并不会直接终止正在进行的请求,它主要是释放内部的
HttpMessageHandler。默认的HttpClientHandler在Dispose时会关闭连接,但如果请求已经处于传输后期(比如响应已经开始返回),底层的连接池机制可能会让请求侥幸完成,不会触发异常。 - 请求完成速度远超预期:Google的响应速度非常快,加上本地可能有DNS缓存或者网络条件极好,
GetStringAsync可能在HttpClient被Dispose之前就已经完成了,这时候await拿到的是已经完成的Task结果,自然不会有问题。 - 异常触发时机的延迟:如果请求还在进行中就释放了HttpClient,异常可能会在读取响应流的阶段抛出,但如果响应已经完整接收,这个阶段就不会执行,也就不会触发异常。
但要注意:这种写法是不安全的,属于潜在的bug!只是你当前的环境没触发异常而已——如果换成网络慢的场景、请求超时,或者调用的是响应慢的接口,大概率会抛出异常导致程序崩溃。
正确的写法应该是给Get方法加上async/await,让using块等到异步请求完成后再释放HttpClient:
public static async Task<string> Get() { using (var http = new HttpClient()) return await http.GetStringAsync("http://google.com"); }
这样await会等待请求完成,之后才会退出using块释放资源,彻底避免资源冲突的问题。
内容的提问来源于stack exchange,提问作者Dominik Przywara
相关产品推荐
相关产品推荐

