我使用Selenium WebDriver和Java中的geckodriver编写了一个Web自动化工具。 目前,每次执行任务时,都会实例化一个新的FirefoxDriver对象。
现在我想实现多线程。我想到的第一种方法是构建类似固定大小的池 - 在启动时实例化X FirefoxDriver对象,将它们包装在带有“inUse”标志的对象中,并使用单例来管理这些实例。
但这是正确的解决方案吗?这是我的第一个Selenium项目,整个概念对我来说都是新的。 经过几天谷歌搜索和阅读文档后,我自己无法找到答案。我真的很感谢你的帮助!
答案 0 :(得分:1)
创建这样的池是完全合理的。我建议使用现有的通用池,例如经典的Commons Pool或更现代的spf4j池,而不是编写自己的池。
要使池工作,您的代码必须在使用后可靠地将驱动程序返回到池中,否则您将泄漏驱动程序(因此也会泄漏整个浏览器实例!)。
因此,我会考虑一种不同的方法:将驱动程序专用于每个线程。您可以使用ThreadLocal:
执行此操作private ThreadLocal<WebDriver> drivers = new ThreadLocal<WebDriver>() {
@Override
protected WebDriver initialValue() {
return new FirefoxDriver(); // or whatever
}
@Override
public void remove() {
WebDriver driver = get();
if (driver != null) driver.close();
super.remove();
}
@Override
public void set(WebDriver value) {
throw new UnsupportedOperationException();
}
};
仍然可能泄漏驱动程序,但仅当线程死亡而没有从ThreadLocal中删除它们的值时。如果你有一个固定的线程池,你可以重复使用,你会没事的。
这种方法的一个缺点是,对于曾经使用过驱动程序的每个线程,你最终得到一个驱动程序,即使并非每个线程都同时使用驱动程序。如果你有一个致力于使用驱动程序的线程池,并且没有其他功能,那么这将不是一个重大问题。但是如果你有一个线程池来完成许多不同类型的工作,那么可能就是这样。