smhy8187

 

在多线程环境下使用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就不能在多线程的环境下调用!

因为目前找不到原因,暂时放在首页,想向各位请教,明天就撤调,请手下留情,谢谢!


 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


Feedback

#1楼    回复  引用    

2005-12-11 12:09 by gzshadow [未注册用户]
我也碰到类似情况,也不知道怎么解决,期待答案

#2楼    回复  引用  查看    

2005-12-11 12:12 by 双鱼座      
不知道有不有人有热情来帮你。既然我来帮你就不能嫌我话多。
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);
}
}
}
}
}

#3楼    回复  引用  查看    

2005-12-11 15:34 by evan      
类似的事情我也做过
有很多可能导致的因素
(1)楼上提到的线程切换的问题
(2)网络带宽的问题(你可以计算下,每个请求返回的数据量)
(3)对方web服务器有可能对同一个ip发起的连续的请求的限制,这也是防止网络攻击的通用做法。具体的内容我不清楚,我之前做过测试,有些web服务器好象总是同时只能接受两个请求,要等response发出之后,才能接受同一个ip的下一个请求

#4楼    回复  引用    

2005-12-12 11:01 by A.Z [未注册用户]
我曾试过100个线程的请求,的确会有超时,首先是网站的问题,IIS对同一IP的并发访问间隔可能有所限制,还有就是网络的问题。最好可以从底层看起。

#5楼    回复  引用  查看    

2005-12-12 11:28 by montaque      
加一行代码就行了

System.Net.ServicePointManager.DefaultConnectionLimit=100

默认你使用webrequest,事实上本质上最多有两个并发的请求. 你改为多个就可以了.



#6楼    回复  引用  查看    

2005-12-12 11:45 by 双鱼座      
montaque是强人!
默认连接限制没有了,但是自由线程限制出来了。当然,自由线程限制也是可以修改的,不过就只能通过修改CLR来控制了。这里有一些示例:
http://www.bearcanyon.com/dotnet/#threading

#7楼    回复  引用    

2005-12-12 14:55 by walkinhill [未注册用户]
谢谢各位的热情帮助:)

双鱼座说的很好,像网络资源确实不能毫不节制的使用,虽说可以通过一些其他的方式来解决现在的问题,但是出发点错了

#8楼    回复  引用    

2006-03-28 15:33 by 天方11 [未注册用户]
为什么我用webrequest循环读网页的时候有时候不能把网页读完整!谢谢!!

#9楼    回复  引用  查看    

2006-04-19 09:17 by blockhead      
比如我有一网址列表,让线程依次对网址请求下载内容,当一个网址时间超时(System.Net.WebException: 操作已超时。)或者相应页面不存在(System.Net.WebException: 远程服务器返回错误: (404) 未找到。)时,我想让程序跳过此网站继续执行请求下一个网址,请问我怎么样实现得到相应服务器返回的错误,并且让其跳过此网址继续执行

#10楼    回复  引用  查看    

2008-08-29 06:58 by upzone      
HttpWebRequest.TimeOut 单位是毫秒,如果数据量大或者请求频繁,我一般把它设大一点

#11楼    回复  引用    

2008-11-03 11:42 by patrickpan [未注册用户]
哥哥,你HttpWebResponse用了以后没有关闭。

#12楼    回复  引用    

2008-11-19 03:00 by chunhong [未注册用户]
11楼一句话解决所有争论,太好了

posted on 2009-03-16 13:21  new2008  阅读(2770)  评论(0编辑  收藏  举报

导航