C# 在.NET中并发运行Selenium时HttpWebRequest超时

C# 在.NET中并发运行Selenium时HttpWebRequest超时,c#,selenium,timeout,threadpool,C#,Selenium,Timeout,Threadpool,我有一个下载工作程序,它使用线程池线程下载文件。在增强这些功能以对下载的文件应用一些Selenium测试之后,我经常遇到文件下载程序超时异常和运行Selenium测试的延迟。更准确地说: 当程序启动时,下载线程开始下载,并且通过Selenium无缝处理两个页面 不久之后,第一个下载线程开始从HttpWebRequest抛出超时异常 同时,命令停止流向Selenium(如SeleniumRC日志中所观察到的),但是运行Selenium的线程没有得到任何异常 只要下载列表中有条目,这种情况就会持续

我有一个下载工作程序,它使用线程池线程下载文件。在增强这些功能以对下载的文件应用一些Selenium测试之后,我经常遇到文件下载程序超时异常和运行Selenium测试的延迟。更准确地说:

  • 当程序启动时,下载线程开始下载,并且通过Selenium无缝处理两个页面
  • 不久之后,第一个下载线程开始从HttpWebRequest抛出超时异常
  • 同时,命令停止流向Selenium(如SeleniumRC日志中所观察到的),但是运行Selenium的线程没有得到任何异常
  • 只要下载列表中有条目,这种情况就会持续:新的下载线程正在启动,并在收到超时后终止(不尝试锁定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,因为我猜SeleniumRC客户端代码也使用HttpWebRequest。看起来我仍然遇到了某种死锁——尽管等待Selenium锁的线程没有任何资源


关于如何使其工作,有什么想法吗?

在深入研究之后,我发现问题与连接无关,而是与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);
}
受保护的void QueueWorkItem(WaitCallback回调,对象状态)
{
//等待可用线程(因为Selenium的异步I/O与ThreadPool混合并产生死锁)
int b,c;
做
{
GetAvailableThreads(out b,out c);
如果(b<10)线程睡眠(250);
}b<10;
//将工作项排队
if(ThreadPool.QueueUserWorkItem(回调,状态))Interlocked.Increment(ref-WorkItemCount);
}

为什么要这样使用selenium?为什么不使用Selenium测试来获取页面,或者使用本机C#测试来获取页面和页面的XML解析器呢?使用Selenium测试来下载页面需要更多(昂贵的)SeleniumRC实例来进行并行化。这就是我为什么要预下载的原因我使用Selenium运行一些我不想移植到C#的JavaScript,这就是为什么我首先让Selenium运行的原因。-使用C#Tests(NUnit)如何解决超时问题?请尝试Selenium Grid并使用PNunit使用Selenium并行测试,或者在JavaScript框架(如JSTestDriver)中运行JavaScript,该框架将针对多个浏览器并行运行JavaScript。使用Selenium测试JavaScript是可行的,但是如果有更适合JS测试的框架,那么执行JavaScript的时间成本可能会很高。谢谢,我将深入研究JSTestDriver。如果有人对上述问题有更多的想法,我仍然会很感激。我在通过并行任务与HttpWebRequest一起运行Selenium时也遇到过类似的问题。最后,唯一的解决办法就是不要让它们彼此并排运行!