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

ChromeDriver配合await Task.WhenAll使用时立即超时问题排查

问题原因

你遇到的提前超时是多个问题叠加导致的:

  • 旧版本Selenium(3.x系列)的HTTP命令执行层存在设计缺陷:所有driver实例默认共享底层HttpClient,且请求生命周期、取消令牌会和当前线程的同步上下文绑定。当你使用await Task.WhenAll()时,运行时默认会捕获调用方的同步上下文(比如WPF/WinForm的UI线程、旧版ASP.NET请求上下文都是单线程同步上下文),等待过程中发生上下文切换时,绑定在原上下文上的HTTP请求取消令牌会被意外触发,直接中止正在发送的WebDriver请求,根本不会走到你配置的120秒超时逻辑。
  • 异常信息里标注的「timed out after 120 seconds」是Selenium包装异常时默认写入的配置值,不是实际等待时长。从内层的SocketException (995)可以看出,请求是发出后1-2秒被本地强制中止的,不是远端WebDriver服务超时。
  • 你在单个任务的catch块中直接调用QuitAllChromeDrivers()会放大故障:只要第一个请求被意外取消抛错,所有其他正在运行的driver进程会被直接关闭,对应HTTP连接全部断开,就会抛出你看到的一连串IO中止异常。

Task.WhenAll(...).Wait()能正常运行的原因很简单:Wait()是同步阻塞调用,不会触发同步上下文的捕获和流转,所有包在Task.Run里的Selenium同步操作会全程运行在独立的线程池线程上,不会出现上下文切换导致的取消令牌误触发问题;同时同步阻塞会触发线程池的线程注入机制,保证并行任务有足够的线程资源运行,不会出现排队。

修复方案

按优先级排序操作即可:

  1. 升级Selenium.WebDriver到4.0以上版本。4.x版本重构了整个HTTP通信层,每个driver实例持有独立的HttpClient,修复了异步上下文下取消令牌误绑定的bug,同时提供了原生的异步API(如GoToUrlAsync()、TitleAsync),从底层避免这类兼容问题。
  2. 如果暂时不能升级Selenium,调用await时添加ConfigureAwait(false),强制不捕获同步上下文,避免上下文切换导致的请求意外取消,修改后的代码为:
    await Task.WhenAll(pages).ConfigureAwait(false);
    
  3. 修正错误处理逻辑:不要在单个并行任务的catch块中直接销毁所有driver,先收集所有任务的执行结果和异常,等所有任务执行完成(无论成功失败)后,再统一做driver资源释放,避免单个任务故障中断所有正常运行的任务。
  4. 不要用Task.Run包裹同步Selenium方法做伪异步。如果要并行执行采集任务,直接用Parallel.ForEach,将并行度设置为和你持有的driver实例数量一致即可,这种纯同步并行的方式不会有异步上下文的兼容问题。

你当前使用的并行采集代码参考如下:

var pages = new List<Task>();
for (var i = 0; i < driverCount; i++)
{
    var driver = _drivers[i];
    var url = urls[urlIndex++];
    Console.WriteLine($"{category.ToUpper()}: {urlIndex} of {urlCount} => {url}");

    pages.Add(Task.Run(() =>
    {
        try
        {
            driver.Navigate().GoToUrl(url);

        }
        catch (Exception e)
        {
            Console.WriteLine("Navigate() EXCEPTION:" + e);
            // 不要在这里直接退出所有driver,标记当前任务失败即可
            throw;
        }
        
        Console.WriteLine($"Parsing: {driver.Url} - {driver.Title}");
        
        // parsing here ...
    }));
}

// 加ConfigureAwait避免同步上下文问题
await Task.WhenAll(pages).ConfigureAwait(false);
// 所有任务执行完成后再统一释放driver资源
QuitAllChromeDrivers();

你遇到的典型异常堆栈参考:

OpenQA.Selenium.WebDriverException: The HTTP request to the remote WebDriver server for URL http://localhost:52594/session/5c138e57c554ccfd59a45b243512c476/title timed out after 120 seconds.
 ---&gt; System.Threading.Tasks.TaskCanceledException: The operation was canceled.
 ---&gt; System.IO.IOException: Unable to read data from the transport connection: The I/O operation has been aborted because of either a thread exit or an application request..
 ---&gt; System.Net.Sockets.SocketException (995): The I/O operation has been aborted because of either a thread exit or an application request.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 04:18:19