C# 在.NET中并发运行Selenium时HttpWebRequest超时
我有一个下载工作程序,它使用线程池线程下载文件。在增强这些功能以对下载的文件应用一些Selenium测试之后,我经常遇到文件下载程序超时异常和运行Selenium测试的延迟。更准确地说:C# 在.NET中并发运行Selenium时HttpWebRequest超时,c#,selenium,timeout,threadpool,C#,Selenium,Timeout,Threadpool,我有一个下载工作程序,它使用线程池线程下载文件。在增强这些功能以对下载的文件应用一些Selenium测试之后,我经常遇到文件下载程序超时异常和运行Selenium测试的延迟。更准确地说: 当程序启动时,下载线程开始下载,并且通过Selenium无缝处理两个页面 不久之后,第一个下载线程开始从HttpWebRequest抛出超时异常 同时,命令停止流向Selenium(如SeleniumRC日志中所观察到的),但是运行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时也遇到过类似的问题。最后,唯一的解决办法就是不要让它们彼此并排运行!