如何异步发送API请求并限流等待,不阻塞主线程?
解决方案
核心问题是Thread.Sleep会同步阻塞当前线程,换成异步等待的await Task.Delay就能解决不阻塞主线程的需求,同时调整计数逻辑确保正确限流。
具体修改步骤:
- 替换同步等待为异步等待:把
Thread.Sleep(60000)改成await Task.Delay(60000),这会让当前异步方法暂停执行60秒,但不会阻塞主线程,其他任务仍能正常运行。 - 重置请求计数:等待完成后必须重置
countMouser,否则会一直触发等待逻辑。 - 确保方法是异步的:包含这段代码的方法必须用
async修饰(比如async Task ProcessComponentsAsync(...)),因为要使用await关键字。
修改后的代码片段:
if (components[0] == "Mouser" && part != components[0]) { // 达到限流阈值时异步等待60秒 if (countMouser >= 30) { await Task.Delay(60000); countMouser = 0; // 重置计数,开始下一轮请求 } string search_api_key = "my_api_key_is_here"; client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); string _partNumber = val; var request = new HttpRequestMessage(HttpMethod.Post, $"https://api.mouser.com/api/v1/search/partnumber?apiKey={search_api_key}"); request.Content = new StringContent($@"{{ ""SearchByPartRequest"": {{ ""mouserPartNumber"": ""{_partNumber}"", ""partSearchOptions"": ""string"" }} }}"); request.Content.Headers.ContentType.MediaType = "application/json"; var response = await client.SendAsync(request, CancellationToken.None); result = await response.Content.ReadAsStringAsync(); countMouser++; // 每次请求成功后计数加1 }
额外优化建议:
- 更精准的速率控制:如果30次请求实际耗时不足60秒,硬等60秒会浪费时间。可以记录每次请求的时间戳,当达到30次时计算需要等待的剩余时间,再调用
Task.Delay。 - 使用CancellationToken:传入
CancellationToken,方便在需要时取消等待和请求,避免无意义的等待。 - 错误处理:添加
try-catch块处理请求失败的情况,避免因为单个请求出错导致整个流程中断,同时可以根据错误类型调整重试逻辑。
内容的提问来源于stack exchange,提问作者user14476651
相关产品推荐
相关产品推荐

