c#如何实现多线程爬虫_c#多线程爬虫的正确用法与注意事项
Task.Run HttpClient 不能直接堆数量跑爬虫因 HttpClient 共享连接池且默认连接上限低.NET Framework 为2、Core/5为10盲目并发会触发 SocketException 或 Connection refused。为什么 Task.Run HttpClient 不能直接堆数量跑爬虫因为 HttpClient 不是线程安全的实例但更关键的是它内部共享连接池盲目开几百个 Task.Run 会迅速打满连接数、触发 SocketException: Too many open files 或 HttpRequestException: Connection refused。默认连接池上限ServicePointManager.DefaultConnectionLimit在 .NET Framework 是 2在 .NET Core/5 是 10远低于你想象的“并发数”。实操建议复用单个 HttpClient 实例推荐声明为 static readonly 或注入 IHttpClientFactory用 SemaphoreSlim 控制并发请求数别依赖线程数——HTTP 请求大部分时间在等响应不是 CPU 密集型设置合理的 Timeout 和 MaxConnectionsPerServer通过 HttpClientHandler 配置避免在循环里 new HttpClient否则 DNS 缓存不生效、TCP 连接无法复用HttpClient 配合 SemaphoreSlim 的最小可靠写法这是真正能控并发、防崩、可重试的组合。重点不是“多线程”而是“可控并发 HTTP 请求流”。示例逻辑.NET 6private static readonly HttpClient _client new HttpClient(new HttpClientHandler{ MaxConnectionsPerServer 100});private static readonly SemaphoreSlim _semaphore new SemaphoreSlim(10, 10); // 最多 10 个并发请求ppublic async Taskstring FetchAsync(string url){await _semaphore.WaitAsync();try{var response await _client.GetAsync(url, CancellationToken);response.EnsureSuccessStatusCode();return await response.Content.ReadAsStringAsync();}finally{_semaphore.Release();}}注意点SemaphoreSlim 必须是 static否则每个实例都独立计数失去限流意义CancellationToken 要传入 GetAsync否则 WaitAsync 被取消时请求还在后台发着别用 Task.WaitAll 等待一堆 Task.Run改用 Task.WhenAll 等待 FetchAsync 返回的 Task遇到 429 / 503 / DNS timeout 怎么办这不是代码写错了是目标站点在反爬或限流。硬扛只会让请求全挂得主动降频、错峰、伪装。 Tellers AI Tellers是一款自动视频编辑工具可以将文本、文章或故事转换为视频。