C#中Selenium启动多个Chrome实例执行JS出现冲突的问题
问题根因
- 核心原因是代码里的
driver字段被定义为了*静态(static)*字段:静态字段属于类级别共享,所有Engine类的实例共用同一个driver存储地址,每次创建新的Engine实例时,都会把静态driver的值覆盖为最新创建的ChromeDriver实例,最终所有实例调用runJs时实际操作的都是最后一次赋值的driver,自然只会在最后启动的Chrome实例上执行JS。 - 调用逻辑存在隐患:你用
ThreadStart搭配异步匿名方法属于async void用法,线程会在第一次await触发时直接退出,同时如果engine是外部声明的共享变量,也会被多次创建的实例覆盖。 - 优化点:
runJs方法用Task.Run包裹同步执行逻辑属于不必要的线程切换,Selenium的ExecuteScript本身是同步阻塞操作,不需要额外包一层Task.Run。
修正方案
第一步:修改Engine类,将driver改为实例字段
public class Engine { // 核心修正:声明为实例私有字段,不要加static修饰 private ChromeDriver driver; public Engine() { var cService = ChromeDriverService.CreateDefaultService(); cService.HideCommandPromptWindow = true; ChromeOptions options = new ChromeOptions(); driver = new ChromeDriver(cService, options); driver.Navigate().GoToUrl("someurl"); } // 优化:去掉不必要的Task.Run,直接同步执行后包装为异步返回 public async Task<object> RunJs(string js) { return await Task.FromResult(((IJavaScriptExecutor)driver.ExecuteScript(js))); // 如果确实需要后台执行也可以保留Task.Run,但一定要确保driver是实例字段 // return await Task.Run(() => ((IJavaScriptExecutor)driver.ExecuteScript(js)); } // 补充:添加资源释放方法,避免Chrome进程残留 public void Dispose() { driver?.Quit(); driver?.Dispose(); } }
第二步:修正调用逻辑
// 改用Task.Run启动异步操作,不要用Thread搭配async void _ = Task.Run(async () => { // engine声明为局部变量,不要用外部共享的变量 var engine = new Engine(); try { var jsres = await engine.RunJs("some simple js code"); Console.WriteLine(jsres); } finally { engine.Dispose(); } });
注意事项
- 每个ChromeDriver实例对应一个独立的Chrome进程,创建多个实例时注意控制资源占用,用完及时调用
Dispose释放,避免后台残留Chrome进程。 - 如果需要并发执行多个实例的JS操作,确保每个实例的driver都是独立的实例字段,不要共享静态driver对象。
内容的提问来源于stack exchange,提问作者Meisam Hashemi
相关产品推荐
相关产品推荐

