gpt4 book ai didi

c# - SpinWait.SpinUntil 在等待 Selenium 元素存在时花费的时间比超时时间长得多

转载 作者:行者123 更新时间:2023-12-04 08:36:50 31 4
gpt4 key购买 nike

我有一个相对简单的方法来等待元素存在并显示。该方法处理为给定 By 返回多个元素的情况(通常我们只希望显示其中一个元素,但无论如何该方法将返回找到的第一个显示元素)。
我遇到的问题是,当页面上(根本)没有匹配的元素时,它花费的时间比指定的 TimeSpan 多*,我不知道为什么。
*我刚刚测试了 30 秒的超时时间,花了 5m 多一点
代码:

    /// <summary>
/// Returns the (first) element that is displayed when multiple elements are found on page for the same by
/// </summary>
public static IWebElement FindDisplayedElement(By by, int secondsToWait = 30)
{
WebDriver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(secondsToWait);
// Wait for an element to exist and also displayed
IWebElement element = null;
bool success = SpinWait.SpinUntil(() =>
{
var collection = WebDriver.FindElements(by);
if (collection.Count <= 0)
return false;
element = collection.ToList().FirstOrDefault(x => x.Displayed == true);
return element != null;
}
, TimeSpan.FromSeconds(secondsToWait));

if (success)
return element;
// if element still not found
throw new NoSuchElementException("Could not find visible element with by: " + by.ToString());
}
你会用这样的东西来调用它:
    [Test]
public void FindDisplayedElement()
{
webDriver.Navigate().GoToUrl("https://stackoverflow.com/questions");
var nonExistenetElementBy = By.CssSelector("#custom-header99");
FindDisplayedElement(nonExistenetElementBy , 10);
}
如果您运行测试(超时 10 秒),您会发现实际退出大约需要 100 秒。
看起来它可能与包含在 SpinWait.WaitUntil() 中的 WebDriver.FindElements() 中内置的继承等待的混合有关。
想听听你们对这个难题的看法。
干杯!

最佳答案

那是因为 SpinWait.WaitUntil大致实现如下:

public static bool SpinUntil(Func<bool> condition, TimeSpan timeout) {
int millisecondsTimeout = (int) timeout.TotalMilliseconds;
long num = 0;
if (millisecondsTimeout != 0 && millisecondsTimeout != -1)
num = Environment.TickCount;
SpinWait spinWait = new SpinWait();
while (!condition())
{
if (millisecondsTimeout == 0)
return false;
spinWait.SpinOnce();
// HERE
if (millisecondsTimeout != -1 && spinWait.NextSpinWillYield && millisecondsTimeout <= (Environment.TickCount - num))
return false;
}
return true;
}
注意上面“HERE”注释下的条件。它只检查超时是否已过期 IF spinWait.NextSpinWillYield返回真。这意味着:如果下一次旋转将导致上下文切换并且超时到期 - 放弃并返回。但除此之外 - 甚至不检查超时就继续旋转。 NextSpinWillYield结果取决于之前的旋转次数。基本上这个构造旋转 X 次(我相信是 10 次),然后开始屈服(将当前线程时间片交给其他线程)。
在您的情况下,条件在 SpinUntil 内需要很长时间来评估,这完全违背 SpinWait 的设计——它期望条件评估根本不需要时间(并且 SpinWait 实际适用的地方——这是真的)。假设对您的情况进行一次条件评估需要 5 秒。然后,即使超时是 1 秒 - 它会在检查超时之前先旋转 10 次(总共 50 秒)。那是因为 SpinWait 不是为您尝试使用它的目的而设计的。来自 documentation :

System.Threading.SpinWait is a lightweight synchronization type thatyou can use in low-level scenarios to avoid the expensive contextswitches and kernel transitions that are required for kernel events.On multicore computers, when a resource is not expected to be held forlong periods of time, it can be more efficient for a waiting thread tospin in user mode for a few dozen or a few hundred cycles, and thenretry to acquire the resource. If the resource is available afterspinning, then you have saved several thousand cycles. If the resourceis still not available, then you have spent only a few cycles and canstill enter a kernel-based wait. This spinning-then-waitingcombination is sometimes referred to as a two-phase wait operation.


在我看来,这些都不适用于您的情况。文档的另一部分指出“SpinWait 通常对普通应用程序没有用”。
在这种情况下,有这么长的条件评估时间 - 您可以在循环中运行它而无需额外等待或旋转,并手动检查每次迭代是否超时。

关于c# - SpinWait.SpinUntil 在等待 Selenium 元素存在时花费的时间比超时时间长得多,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64763173/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com