使用BenchmarkDotNet测试异步任务:代码运行问题咨询
解决BenchmarkDotNet异步任务性能测试的问题
嘿,我看你这段BenchmarkDotNet的异步测试代码里有几个明显的坑,咱们一个个捋清楚:
问题1:静态字段提前执行异步方法
你把ParseNewton()和ParseServiceStack()直接赋值给静态字段newton和servicestack了,这会在类第一次被加载的时候就自动执行这些异步方法,完全脱离了BenchmarkDotNet的测试控制逻辑。Benchmark需要每次测试都重新执行目标方法来获取准确的性能数据,你这样提前执行的话,最终测试的可能只是任务的等待结果,根本不是真正的解析性能。
问题2:异步方法里用同步阻塞调用
你在ParseNewton()里用了client.GetAsync(Url).Result,这是典型的“异步转同步”的错误写法,不仅会破坏异步代码的优势,还可能在某些同步上下文里导致死锁。而且BenchmarkDotNet原生支持异步方法的测试,完全没必要这么干。
修正后的代码示例
public class ParsingBenchmarks { private const string Url = "blabla"; // 单例HttpClient是最佳实践,没问题 private static readonly HttpClient _client = new HttpClient(); // 去掉提前初始化的静态任务字段,让Benchmark方法自己控制执行时机 [Benchmark] public async Task<string> ParseNewton() { // 把.Result改成await,保持异步流程 var response = await _client.GetAsync(Url).ConfigureAwait(false); var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); var serializer = new Newtonsoft.Json.JsonSerializer(); using var reader = new StreamReader(stream); using var jsonReader = new Newtonsoft.Json.JsonTextReader(reader); return serializer.Deserialize<string>(jsonReader); } [Benchmark] public async Task<string> ParseServiceStack() { var response = await _client.GetAsync(Url).ConfigureAwait(false); var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); // 这里补充ServiceStack的解析逻辑 return ServiceStack.Text.JsonSerializer.DeserializeFromString<string>(await new StreamReader(stream).ReadToEndAsync().ConfigureAwait(false)); } }
额外注意事项
- Benchmark方法的签名必须是
async Task或async Task<T>,你原来的方法签名是对的,但要确保方法内部没有同步阻塞的代码(比如.Result、.Wait())。 - 如果你的测试需要避免请求缓存影响结果,可以考虑给Url加随机参数,或者在Benchmark的
[GlobalSetup]里做一些初始化准备。 - 记得给Benchmark类加上
[MemoryDiagnoser]之类的特性,能同时获取内存分配数据,让测试结果更全面。
内容的提问来源于stack exchange,提问作者Cholesterol
相关产品推荐
相关产品推荐

