在多线程环境下使用HttpWebRequest或者调用Web Service
最近使用多线程同时调用一个Web Service,总是有很多调用报超时,代码类似于下面的代码(为了简化,我把调用Web Service改为使用HttpWebRequest访问一个网址,效果时一样的):
我循环调用100次,但是总是有几十次调用报超时,具体如下:
System.Net.WebException: 操作已超时。
at System.Net.HttpWebRequest.GetResponse()
at HttpRequestTest.HttpRequestTest.MakeWebRequest(Object obj) in g:\my documents\visual studio projects\httprequesttest\httprequesttest.cs:line 35
真的不知道为什么,难道Web Service就不能在多线程的环境下调用!
因为目前找不到原因,暂时放在首页,想向各位请教,明天就撤调,请手下留情,谢谢!
我循环调用100次,但是总是有几十次调用报超时,具体如下:
System.Net.WebException: 操作已超时。
at System.Net.HttpWebRequest.GetResponse()
at HttpRequestTest.HttpRequestTest.MakeWebRequest(Object obj) in g:\my documents\visual studio projects\httprequesttest\httprequesttest.cs:line 35
真的不知道为什么,难道Web Service就不能在多线程的环境下调用!
因为目前找不到原因,暂时放在首页,想向各位请教,明天就撤调,请手下留情,谢谢!
1using System;
2using System.Diagnostics;
3using System.Net;
4using System.Threading;
5
6namespace HttpRequestTest
7{
8 /// <summary>
9 /// Class1 的摘要说明。
10 /// </summary>
11 class HttpRequestTest
12 {
13
14 //[STAThread]
15 static void Main(string[] args)
16 {
17 for(int i = 0; i < 100; i++ )
18 {
19 ThreadPool.QueueUserWorkItem(new WaitCallback(MakeWebRequest),"http://www.163.com");
20 }
21 Console.ReadLine();
22 }
23
24 private static void MakeWebRequest (object obj)
25 {
26 string url = obj as string;
27 HttpWebResponse res = null;
28 try
29 {
30 HttpWebRequest req = (HttpWebRequest)WebRequest.Create (url);
31 req.Timeout = 15000;
32
33 Console.WriteLine ("\nConnecting to " + url + " ");
34
35 res = (HttpWebResponse)req.GetResponse ();
36
37 Console.WriteLine("[" + AppDomain.GetCurrentThreadId() + "] ContentLength:" + res.ContentLength);
38 Console.WriteLine ("Connected.\n");
39
40
41 }
42 catch (Exception e)
43 {
44 Console.WriteLine ("Source : " + e.Source);
45 Console.WriteLine ("Message : " + e.Message);
46 Console.WriteLine(e.ToString());
47 Debug.WriteLine(e.ToString());
48 //Console.WriteLine("StackTrace :" + e.StackTrace);
49 }
50 finally
51 {
52 if (res != null)
53 {
54 res.Close ();
55 }
56 }
57 }
58 }
59}
60
2using System.Diagnostics;
3using System.Net;
4using System.Threading;
5
6namespace HttpRequestTest
7{
8 /// <summary>
9 /// Class1 的摘要说明。
10 /// </summary>
11 class HttpRequestTest
12 {
13
14 //[STAThread]
15 static void Main(string[] args)
16 {
17 for(int i = 0; i < 100; i++ )
18 {
19 ThreadPool.QueueUserWorkItem(new WaitCallback(MakeWebRequest),"http://www.163.com");
20 }
21 Console.ReadLine();
22 }
23
24 private static void MakeWebRequest (object obj)
25 {
26 string url = obj as string;
27 HttpWebResponse res = null;
28 try
29 {
30 HttpWebRequest req = (HttpWebRequest)WebRequest.Create (url);
31 req.Timeout = 15000;
32
33 Console.WriteLine ("\nConnecting to " + url + " ");
34
35 res = (HttpWebResponse)req.GetResponse ();
36
37 Console.WriteLine("[" + AppDomain.GetCurrentThreadId() + "] ContentLength:" + res.ContentLength);
38 Console.WriteLine ("Connected.\n");
39
40
41 }
42 catch (Exception e)
43 {
44 Console.WriteLine ("Source : " + e.Source);
45 Console.WriteLine ("Message : " + e.Message);
46 Console.WriteLine(e.ToString());
47 Debug.WriteLine(e.ToString());
48 //Console.WriteLine("StackTrace :" + e.StackTrace);
49 }
50 finally
51 {
52 if (res != null)
53 {
54 res.Close ();
55 }
56 }
57 }
58 }
59}
60
Feedback
#1楼 回复 引用
2005-12-11 12:09 by gzshadow [未注册用户]我也碰到类似情况,也不知道怎么解决,期待答案
不知道有不有人有热情来帮你。既然我来帮你就不能嫌我话多。
1.下次你不要将你的代码加上行号,很讨厌的,这样别人没法直接copy/paste到自己的编辑器中。
2.网络是个竞争性很强的资源,在单CPU的多线程环境下15000可能是不够的,特别是很大的response并且网络带宽有限的时候。除了请求端的线程竞争还有返回端的线程竞争(返回端的线程竞争是在系统内核模态而不是在用户模态)。感觉你这样疯狂地用线程是非常不恰当的。我将次数改为20就通过了。
3.当然,你会说我篡改了你的需求,你的确要求100个并发任务。但是你必须限制你对线程的无限制使用,当线程与CPU个数之间的比例非常离谱的时候,你的CPU都是在忙于线程之间的调度了,没有时间处理你的任务。
4.其实整件事情是因为你对线程的放任使用所导致的,与HttpWebRequest或者Web Services没有任何关系。不信你可以试试任何一个长任务。不过这种情况在网络任务方面特别典型。
以下是我改过的代码:
using System;
using System.Diagnostics;
using System.Threading;
using System.Net;
namespace MultiThread
{
/// <summary>
/// Class1 的摘要说明。
/// </summary>
class Class1
{
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main(string[] args)
{
Thread thread = new Thread(new ThreadStart(MakeThread));
thread.Start();
Console.ReadLine();
}
private static int count = 30;
private static int max = 10;
private static int x = 0;
private static int y = 0;
private static void MakeThread()
{
while (x < count)
{
if (y < max)
{
HttpWebRequest req = (HttpWebRequest)WebRequest.Create ("http://www.google.com"/);
req.Timeout = 100000;
ThreadPool.QueueUserWorkItem(new WaitCallback(MakeWebRequest), req);
Interlocked.Increment(ref y);
}
Thread.Sleep(0);
}
Console.WriteLine("=======================================");
}
private static void MakeWebRequest (object obj)
{
HttpWebRequest req = obj as HttpWebRequest;
HttpWebResponse res = null;
try
{
Console.WriteLine ("\nConnecting to " + req.RequestUri);
res = (HttpWebResponse) req.GetResponse ();
Console.WriteLine("[" + AppDomain.GetCurrentThreadId() + "] ContentLength:" + res.ContentLength);
Console.WriteLine ("Connected.\n");
}
catch (Exception e)
{
if (res != null)
{
res.Close ();
Interlocked.Increment(ref x);
Interlocked.Decrement(ref y);
res = null;
}
Console.WriteLine ("Source : " + e.Source);
Console.WriteLine ("Message : " + e.Message);
Console.WriteLine(e.ToString());
Debug.WriteLine(e.ToString());
}
finally
{
if (res != null)
{
res.Close ();
Interlocked.Increment(ref x);
Interlocked.Decrement(ref y);
}
}
}
}
}
1.下次你不要将你的代码加上行号,很讨厌的,这样别人没法直接copy/paste到自己的编辑器中。
2.网络是个竞争性很强的资源,在单CPU的多线程环境下15000可能是不够的,特别是很大的response并且网络带宽有限的时候。除了请求端的线程竞争还有返回端的线程竞争(返回端的线程竞争是在系统内核模态而不是在用户模态)。感觉你这样疯狂地用线程是非常不恰当的。我将次数改为20就通过了。
3.当然,你会说我篡改了你的需求,你的确要求100个并发任务。但是你必须限制你对线程的无限制使用,当线程与CPU个数之间的比例非常离谱的时候,你的CPU都是在忙于线程之间的调度了,没有时间处理你的任务。
4.其实整件事情是因为你对线程的放任使用所导致的,与HttpWebRequest或者Web Services没有任何关系。不信你可以试试任何一个长任务。不过这种情况在网络任务方面特别典型。
以下是我改过的代码:
using System;
using System.Diagnostics;
using System.Threading;
using System.Net;
namespace MultiThread
{
/// <summary>
/// Class1 的摘要说明。
/// </summary>
class Class1
{
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main(string[] args)
{
Thread thread = new Thread(new ThreadStart(MakeThread));
thread.Start();
Console.ReadLine();
}
private static int count = 30;
private static int max = 10;
private static int x = 0;
private static int y = 0;
private static void MakeThread()
{
while (x < count)
{
if (y < max)
{
HttpWebRequest req = (HttpWebRequest)WebRequest.Create ("http://www.google.com"/);
req.Timeout = 100000;
ThreadPool.QueueUserWorkItem(new WaitCallback(MakeWebRequest), req);
Interlocked.Increment(ref y);
}
Thread.Sleep(0);
}
Console.WriteLine("=======================================");
}
private static void MakeWebRequest (object obj)
{
HttpWebRequest req = obj as HttpWebRequest;
HttpWebResponse res = null;
try
{
Console.WriteLine ("\nConnecting to " + req.RequestUri);
res = (HttpWebResponse) req.GetResponse ();
Console.WriteLine("[" + AppDomain.GetCurrentThreadId() + "] ContentLength:" + res.ContentLength);
Console.WriteLine ("Connected.\n");
}
catch (Exception e)
{
if (res != null)
{
res.Close ();
Interlocked.Increment(ref x);
Interlocked.Decrement(ref y);
res = null;
}
Console.WriteLine ("Source : " + e.Source);
Console.WriteLine ("Message : " + e.Message);
Console.WriteLine(e.ToString());
Debug.WriteLine(e.ToString());
}
finally
{
if (res != null)
{
res.Close ();
Interlocked.Increment(ref x);
Interlocked.Decrement(ref y);
}
}
}
}
}
类似的事情我也做过
有很多可能导致的因素
(1)楼上提到的线程切换的问题
(2)网络带宽的问题(你可以计算下,每个请求返回的数据量)
(3)对方web服务器有可能对同一个ip发起的连续的请求的限制,这也是防止网络攻击的通用做法。具体的内容我不清楚,我之前做过测试,有些web服务器好象总是同时只能接受两个请求,要等response发出之后,才能接受同一个ip的下一个请求
有很多可能导致的因素
(1)楼上提到的线程切换的问题
(2)网络带宽的问题(你可以计算下,每个请求返回的数据量)
(3)对方web服务器有可能对同一个ip发起的连续的请求的限制,这也是防止网络攻击的通用做法。具体的内容我不清楚,我之前做过测试,有些web服务器好象总是同时只能接受两个请求,要等response发出之后,才能接受同一个ip的下一个请求
#4楼 回复 引用
2005-12-12 11:01 by A.Z [未注册用户]我曾试过100个线程的请求,的确会有超时,首先是网站的问题,IIS对同一IP的并发访问间隔可能有所限制,还有就是网络的问题。最好可以从底层看起。
加一行代码就行了
System.Net.ServicePointManager.DefaultConnectionLimit=100
默认你使用webrequest,事实上本质上最多有两个并发的请求. 你改为多个就可以了.
System.Net.ServicePointManager.DefaultConnectionLimit=100
默认你使用webrequest,事实上本质上最多有两个并发的请求. 你改为多个就可以了.
montaque是强人!
默认连接限制没有了,但是自由线程限制出来了。当然,自由线程限制也是可以修改的,不过就只能通过修改CLR来控制了。这里有一些示例:
http://www.bearcanyon.com/dotnet/#threading
默认连接限制没有了,但是自由线程限制出来了。当然,自由线程限制也是可以修改的,不过就只能通过修改CLR来控制了。这里有一些示例:
http://www.bearcanyon.com/dotnet/#threading
#7楼 回复 引用
2005-12-12 14:55 by walkinhill [未注册用户]谢谢各位的热情帮助:)
双鱼座说的很好,像网络资源确实不能毫不节制的使用,虽说可以通过一些其他的方式来解决现在的问题,但是出发点错了
双鱼座说的很好,像网络资源确实不能毫不节制的使用,虽说可以通过一些其他的方式来解决现在的问题,但是出发点错了
#8楼 回复 引用
2006-03-28 15:33 by 天方11 [未注册用户]为什么我用webrequest循环读网页的时候有时候不能把网页读完整!谢谢!!
比如我有一网址列表,让线程依次对网址请求下载内容,当一个网址时间超时(System.Net.WebException: 操作已超时。)或者相应页面不存在(System.Net.WebException: 远程服务器返回错误: (404) 未找到。)时,我想让程序跳过此网站继续执行请求下一个网址,请问我怎么样实现得到相应服务器返回的错误,并且让其跳过此网址继续执行
#11楼 回复 引用
2008-11-03 11:42 by patrickpan [未注册用户]哥哥,你HttpWebResponse用了以后没有关闭。
#12楼 回复 引用
2008-11-19 03:00 by chunhong [未注册用户]11楼一句话解决所有争论,太好了