SpinWait.SpinUntil,直到等待Selnium元素存在之前,需要花费比超时更长的时间才能退出

我有一个相对简单的方法来等待元素存在并显示出来。该方法可以处理为给定的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()中内置的继承等待的混合有关。

想听听你们对这个难题的看法。

干杯!

ssywzssywz 回答:SpinWait.SpinUntil,直到等待Selnium元素存在之前,需要花费比超时更长的时间才能退出

这是因为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”注释下的条件。仅在spinWait.NextSpinWillYield返回true时检查超时是否已到期。这意味着:如果下一次旋转将导致上下文切换并且超时已过期,请放弃并返回。否则,请保持旋转,甚至不检查超时。

NextSpinWillYield的结果取决于先前旋转的次数。基本上,此构造旋转X次(我相​​信是10次),然后开始产生(将当前线程时间片分配给其他线程)。

在您的情况下,SpinUntil中的条件要花很长时间才能评估,这完全与SpinWait的设计背道而驰-它期望条件评估根本不需要时间(并且在SpinWait实际适用的地方-确实如此)。说您的情况评估一次需要5秒钟。然后,即使超时为1秒,它也会先旋转10次(总共50秒),然后再检查超时。这是因为SpinWait并非针对您要使用它的东西而设计。来自documentation

System.Threading.SpinWait是一种轻量级同步类型,它可以 您可以在低级方案中使用以避免昂贵的上下文 内核事件所需的开关和内核转换。 在多核计算机上,当预计不保留资源时 长时间,等待线程可以更高效 在用户模式下旋转几十个或几百个周期,然后 重试获取资源。如果资源在之后可用 旋转,那么您已经节省了数千个循环。如果资源 仍然不可用,那么您只花了几个周期就可以 仍然输入基于内核的等待。旋转然后等待 组合有时称为两阶段等待操作。

我认为,这都不适合您的情况。文档的另一部分指出“ SpinWait通常不适用于普通应用程序”。

在这种情况下,条件评估时间如此之长-您可以在循环中运行它而无需额外的等待或旋转,并手动检查每次迭代的超时时间是否已到期。

,

进行一些进一步的测试后,我发现将WebDriver隐式等待超时减小为一个较小的数字(例如100ms)可以解决此问题。这与提供@Evk的解释有关为何无法使用SpinUntil的解释。

我将功能更改为改为使用WebDriverWait(如in this answer to a different question所示),它现在可以正常工作。这样就完全不需要使用隐式等待超时了。

    /// <summary>
    /// Returns the (first) element that is displayed when multiple elements are found on page for the same by
    /// </summary>
    /// <exception cref="NoSuchElementException">Thrown when either an element is not found or none of the found elements is displayed</exception>
    public static IWebElement FindDisplayedElement(By by,int secondsToWait = DEFAULT_WAIT)
    {
        var wait = new WebDriverWait(WebDriver,TimeSpan.FromSeconds(secondsToWait));
        try
        {
            return wait.Until(condition =>
            {
                return WebDriver.FindElements(by).ToList().FirstOrDefault(x => x.Displayed == true);
            });
        }
        catch (WebDriverTimeoutException ex)
        {
            throw new NoSuchElementException("Could not find visible element with by: " + by.ToString(),ex);
        }
    }
本文链接:https://www.f2er.com/1245130.html

大家都在问