在多线程环境下使用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就不能在多线程的环境下调用!
因为目前找不到原因,暂时放在首页,想向各位请教,明天就撤调,请手下留情,谢谢!
1
using System;
2
using System.Diagnostics;
3
using System.Net;
4
using System.Threading;
5
6
namespace 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.下次你不要将你的代码加上行号,很讨厌的,这样别人没法直接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的下一个请求