在.NET中同时运行Selenium时使用HttpWebRequest的TimeOuts

时间:2010-03-24 08:23:54

标签: c# selenium timeout threadpool

我有一个使用ThreadPool-threads下载文件的下载工作者。在对这些文件进行增强后,将一些Selenium测试应用于下载的文件,我经常遇到文件下载的TimeOut异常和运行Selenium测试的延迟。更确切地说:

  • 当程序启动时,下载线程开始下载,并通过Selenium无缝处理几页
  • 不久之后,第一个下载线程开始从HttpWebRequest中抛出TimeOut异常。
  • 同时,命令停止流向Selenium(如SeleniumRC日志中所示),但运行Selenium的线程没有任何异常
  • 只要下载列表中有条目,就会出现这种情况:新的下载线程正在启​​动并在收到TimeOuts后终止(不试图锁定Selenium)
  • 一旦没有更多的下载线程被启动,Selenium就会再次开始接收命令,等待锁定的线程按照设计顺序处理

现在这里是下载代码:

HttpWebRequest request = null;
WebResponse response = null;
Stream stream = null;
StreamReader sr = null;
try
{
    request = (HttpWebRequest) WebRequest.Create(uri);
    request.ServicePoint.ConnectionLimit = MAX_CONNECTIONS_PER_HOST;
    response = request.GetResponse();
    stream = response.GetResponseStream();
    // Read the stream...
}
finally
{
    if (request != null) request.Abort();
    if (response != null) response.Close();
    if (stream != null)
    {
        stream.Close();
        stream.Dispose();
    }
    if (sr != null)
    {
        sr.Close();
        sr.Dispose();
    }
}

这就是Selenium之后在同一个线程中使用的方式:

lock(SeleniumLock)
{
    selenium.Open(url);
    // Run some Selenium commands, but no selenium.stop()
}

其中selenium是在类的静态构造函数中初始化的静态变量(通过selenium.start())。

我假设我遇到了CLR连接限制,所以我在初始化过程中添加了这些行:

ThreadPool.GetMaxThreads (out maxWorkerThreads, out maxCompletionPortThreads);
HttpUtility.MAX_CONNECTIONS_PER_HOST = maxWorkerThreads;
System.Net.ServicePointManager.DefaultConnectionLimit = maxWorkerThreads + 1;

+ 1用于连接到SeleniumRC,因为我猜测Selenium客户端代码也使用了HttpWebRequest。看起来我仍然遇到某种死锁 - 虽然等待Selenium锁的线程没有任何资源。

有关如何使其发挥作用的任何想法?

1 个答案:

答案 0 :(得分:1)

在深入研究之后,我认为该问题与连接有关,而与ThreadPool和HttpWebRequest无关:在下载程序开始遇到超时的时间点,ThreadPool.GetAvailableThreads()返回0或-1可用工人线程。我小心翼翼地选择同步使用HttpWebRequest以确保不会发生这种情况。据推测,Selenium客户端驱动程序使用异步方法,产生这种“线程死锁”。

我不确定解决此问题的最佳方法是什么,但ThreadPool.QueueUserWorkItem()的替代方法替代了该程序至少可用:

protected void QueueWorkItem(WaitCallback callBack, object state)
{
    // Wait for available thread (as Selenium's async I/O is mixed with ThreadPool and yields deadlocks)
    int b, c;
    do
    {
        ThreadPool.GetAvailableThreads(out b, out c);
        if (b < 10) Thread.Sleep(250);
    } while (b < 10);
    // Queue the work item
    if (ThreadPool.QueueUserWorkItem(callBack, state)) Interlocked.Increment(ref WorkItemCount);
}