首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在等待Selnium元素存在时,SpinWait.SpinUntil的退出时间要比超时时间长得多

在等待Selnium元素存在时,SpinWait.SpinUntil的退出时间要比超时时间长得多
EN

Stack Overflow用户
提问于 2020-11-10 05:04:37
回答 2查看 510关注 0票数 2

我有一个相对简单的方法来等待元素存在并显示出来。该方法处理的情况是,为指定的对象返回一个以上的元素(通常我们只希望显示其中的一个元素,但无论如何,该方法将返回找到的第一个显示的元素)。

我遇到的问题是,当页面上没有匹配的元素时,所花费的时间要比指定的TimeSpan多*,我不知道为什么。

*我刚测试了30分钟的超时时间,花费了5米多一点

代码:

代码语言:javascript
复制
    /// <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());
    }

你可以这样称呼它:

代码语言:javascript
复制
    [Test]
    public void FindDisplayedElement()
    {
       webDriver.Navigate().GoToUrl("https://stackoverflow.com/questions");
       var nonExistenetElementBy = By.CssSelector("#custom-header99");
       FindDisplayedElement(nonExistenetElementBy , 10);
    }

如果您运行测试(有10秒超时),您会发现实际退出大约需要100秒钟。

看起来,这可能与封装在WebDriver.FindElements()中的SpinWait.WaitUntil()中内置的继承等待的混合有关。

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

干杯!

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-11-10 08:11:28

通过进一步的测试,我发现将WebDriver隐式等待超时减少到一个较低的数目(例如100 to )可以解决这个问题。这与@Evk给出的为什么使用SpinUntil不起作用的解释相对应。

我已经将函数改为使用WebDriverWait (如对另一个问题的回答所示),现在它正确工作了。这完全消除了使用隐式等待超时的需要。

代码语言:javascript
复制
    /// <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);
        }
    }
票数 0
EN

Stack Overflow用户

发布于 2020-11-10 07:34:17

这是因为SpinWait.WaitUntil按如下方式实现:

代码语言:javascript
复制
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;
}

请注意上面“这里”注释下面的条件。它只检查spinWait.NextSpinWillYield返回true时超时是否已过期。这意味着:如果下一个旋转将导致上下文切换和超时过期-放弃并返回。但否则-继续旋转甚至不检查超时。

NextSpinWillYield结果取决于以前的自旋数。基本上,这个构造旋转X次(我相信10次),然后开始产生(将当前线程时间切片让给其他线程)。

在您的例子中,SpinUntil内部的条件需要很长的时间来评估,这完全违背了SpinWait的设计--它期望条件评估完全不需要时间(而SpinWait实际上是适用的--这是真的)。假设在你的情况下,一次状态评估需要5秒。然后,即使超时是1秒-它将旋转10倍的第一个(50秒总数),甚至检查超时。这是因为SpinWait不是为您试图使用它的东西而设计的。来自文档

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

在我看来,这些都不适用于你的情况。文档的另一部分声明"SpinWait对于普通应用程序通常并不有用“。

在这种情况下,使用如此长的条件评估时间-您可以只在一个循环中运行它而不需要额外的等待或旋转,并且手动检查每次迭代是否超时。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64763173

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档