我写了一个程序关于httpWebRequest异步获取网站内容,在开始时没有什么问题,问题出在关闭所有线程的时候,
已经发出去的异步请求并没有结束,任务管理器中的线程数反而可能会增加(按机器而定),就算异步执行完毕后,
线程并没有减少内存也在不停的增加。
请问这是怎么回事,请牛人解答
代码如下:using System;
using System.Net;
using System.IO;
using System.Text;
using System.Threading;
public class RequestState
{
  // This class stores the State of the request.
  const int BUFFER_SIZE = 1024;
  public StringBuilder requestData;
  public byte[] BufferRead;
  public HttpWebRequest request;
  public HttpWebResponse response;
  public Stream streamResponse;
  public RequestState()
  {
    BufferRead = new byte[BUFFER_SIZE];
    requestData = new StringBuilder("");
    request = null;
    streamResponse = null;
  }
}class HttpWebRequest_BeginGetResponse
{
    public static ManualResetEvent allDone = new ManualResetEvent(false);
    const int BUFFER_SIZE = 1024;
    const int DefaultTimeout = 2 * 60 * 1000; // 2 minutes timeout
    public delegate void GetDataHandle(string html);
    public event GetDataHandle GetDataEvent;    // Abort the request if the timer fires.
    private void TimeoutCallback(object state, bool timedOut)
    {
        if (timedOut)
        {
            HttpWebRequest request = state as HttpWebRequest;
            if (request != null)
            {
                request.Abort();
            }
        }
    }    public void Request()
    {        try
        {
            // Create a HttpWebrequest object to the desired URL. 
            HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create("http://www.baidu.com");
          // Create an instance of the RequestState and assign the previous myHttpWebRequest
            // object to its request field.  
            RequestState myRequestState = new RequestState();
            myRequestState.request = myHttpWebRequest;
            // Start the asynchronous request.
            IAsyncResult result =
              (IAsyncResult)myHttpWebRequest.BeginGetResponse(new AsyncCallback(RespCallback), myRequestState);            // this line implements the timeout, if there is a timeout, the callback fires and the request becomes aborted
            ThreadPool.RegisterWaitForSingleObject(result.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), myHttpWebRequest, DefaultTimeout, true);            // The response came in the allowed time. The work processing will happen in the 
            // callback function.
            allDone.WaitOne();            // Release the HttpWebResponse resource.
            myRequestState.response.Close();
        }
        catch (WebException e)
        {
            Console.WriteLine("\nMain Exception raised!");
            Console.WriteLine("\nMessage:{0}", e.Message);
            Console.WriteLine("\nStatus:{0}", e.Status);
            Console.WriteLine("Press any key to continue..........");
        }
        catch (Exception e)
        {
            Console.WriteLine("\nMain Exception raised!");
            Console.WriteLine("Source :{0} ", e.Source);
            Console.WriteLine("Message :{0} ", e.Message);
            Console.WriteLine("Press any key to continue..........");
            Console.Read();
        }
    }    private void RespCallback(IAsyncResult asynchronousResult)
    {
        try
        {
            // State of request is asynchronous.
            RequestState myRequestState = (RequestState)asynchronousResult.AsyncState;
            HttpWebRequest myHttpWebRequest = myRequestState.request;
            myRequestState.response = (HttpWebResponse)myHttpWebRequest.EndGetResponse(asynchronousResult);            // Read the response into a Stream object.
            Stream responseStream = myRequestState.response.GetResponseStream();
            myRequestState.streamResponse = responseStream;            // Begin the Reading of the contents of the HTML page and print it to the console.
            IAsyncResult asynchronousInputRead = responseStream.BeginRead(myRequestState.BufferRead, 0, BUFFER_SIZE, new AsyncCallback(ReadCallBack), myRequestState);
            return;
        }
        catch (WebException e)
        {
            Console.WriteLine("\nRespCallback Exception raised!");
            Console.WriteLine("\nMessage:{0}", e.Message);
            Console.WriteLine("\nStatus:{0}", e.Status);
        }
        allDone.Set();
    }
    private void ReadCallBack(IAsyncResult asyncResult)
    {
        try
        {            RequestState myRequestState = (RequestState)asyncResult.AsyncState;
            Stream responseStream = myRequestState.streamResponse;
            int read = responseStream.EndRead(asyncResult);
            // Read the HTML page and then print it to the console.
            if (read > 0)
            {
                myRequestState.requestData.Append(Encoding.ASCII.GetString(myRequestState.BufferRead, 0, read));
                IAsyncResult asynchronousResult = responseStream.BeginRead(myRequestState.BufferRead, 0, BUFFER_SIZE, new AsyncCallback(ReadCallBack), myRequestState);
                return;
            }
            else
            {
                Console.WriteLine("\nThe contents of the Html page are : ");
                if (myRequestState.requestData.Length > 1)
                {
                    string stringContent;
                    stringContent = myRequestState.requestData.ToString();
                    GetDataEvent("成功获取");
                    Console.WriteLine(stringContent);
                }
                Console.WriteLine("Press any key to continue..........");
                Console.ReadLine();                responseStream.Close();
            }        }
        catch (WebException e)
        {
            Console.WriteLine("\nReadCallBack Exception raised!");
            Console.WriteLine("\nMessage:{0}", e.Message);
            Console.WriteLine("\nStatus:{0}", e.Status);
        }
        allDone.Set();    }
}

解决方案 »

  1.   

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Text;
    using System.Windows.Forms;
    using System.Threading;
    namespace TestThread
    {
        public partial class Form1 : Form
        {
            List<Thread> listThread = new List<Thread>();
            bool blTag;        public Form1()
            {
                InitializeComponent();
                CheckForIllegalCrossThreadCalls = false;
            }        private void button1_Click(object sender, EventArgs e)
            {
                Thread newThread = null;
                
                for(int i=0;i<20;i++)
                {
                    newThread = new Thread(process);
                    newThread.Start();
                    listThread.Add(newThread);
                }
                this.button2.Enabled = true;
                this.button1.Enabled = false;
            }
            HttpWebRequest_BeginGetResponse instance;
            private void process()
            {
                instance = new HttpWebRequest_BeginGetResponse();
                instance.GetDataEvent += new HttpWebRequest_BeginGetResponse.GetDataHandle(instance_GetDataEvent);
                while (!blTag)
                {
                    instance.Request();
                }
                
            }        void instance_GetDataEvent(string html)
            {
                this.textBox1.AppendText(html+"r\n");
                textBox1.SelectionStart = textBox1.Text.Length;
                textBox1.Focus();
            }        private void button2_Click(object sender, EventArgs e)
            {
                blTag = true;
                foreach (Thread newThread in listThread)
                {
                    newThread.Abort();
                }            this.button1.Enabled = true;
                this.button2.Enabled = false;            foreach (Thread newThread in listThread)
                {
                    if (newThread.IsAlive == true)
                        return;
                }
                listThread.Clear();           
            }
         }
    }
      

  2.   

    没看明白,
    Async 调用机制跟 Thread/ ManualResetEvent 混合使用有点乱
      

  3.   

    上面HttpWebRequest_BeginGetResponse类,来自于MSDN上,你说有点乱,哪里乱了,能说清楚一些吗
      

  4.   


            private void process()
            {
                instance = new HttpWebRequest_BeginGetResponse();
                instance.GetDataEvent += new HttpWebRequest_BeginGetResponse.GetDataHandle(instance_GetDataEvent);
                while (!blTag)   // 主要问题在这里  线程中还在循环,这里每循环一次由于你的request是异步的   都会产生新的线程  瞬间可能打到线程上限
                {
                    instance.Request();
                }
            }
    void instance_GetDataEvent(string html)  //跨线程操作textBox ,会有问题
            {
                this.textBox1.AppendText(html+"r\n");
                textBox1.SelectionStart = textBox1.Text.Length;
                textBox1.Focus();
            }
     foreach (Thread newThread in listThread)  //你根本不只20个线程
                {
                    newThread.Abort();
                }
      

  5.   

    费时间看HttpWebRequest_BeginGetResponse好久
    不是那儿的问题
    你使用的问题
      

  6.   

    前天才开始看线程.
    可能代码不完整.不知道你哪里用到了自己new出来的那20个线程.
    委托异步会自己建线程.当然.net在委托方法后会自动帮你关掉。
    你不按button2.一直会建立新线程.太不可取了吧.
    好象并没有直接获取当前运用程序线程数量的函数。
    自己想办法判断吧.
    用一个 int 来记录?调用方法前+1.结束后-1?
      

  7.   

    不是关不关的问题。
    就算你手动关掉.你那个while (!blTag)语句.什么电脑受的了。
      

  8.   

    我用while(!blTag)只是做个实验,其实我程序中当有可用地址时才去执行这个异步。
    异步委托方法结束后并不会结束异步产生的线程。
      

  9.   

    刚好自己也在看线程.
    所以测试了了下。
    大哥,你的代码是从别的地方copy过来的吧.呵呵。
    void instance_GetDataEvent(string html)
            {
                this.textBox1.AppendText(html+"r\n");
                textBox1.SelectionStart = textBox1.Text.Length;
                textBox1.Focus();
            }
    这个代码我不知道你是否可以执行.
    异步建立的线程.回调这个函数.但是这个线程的上下文应该是不会存在textbox1的。除非你在次线程中new了它.
    或者是你代码不完整.还有你的代码中本来就是ThreadPool.线程池了。到前台开多线程不知道什么用意.
    而且.你获取的是一个网页的数据.并不是多个网页.用多线程怎么处理?我搞晕了。我用了你前面的代码.后面写一点代码就可以了。private void button1_Click(object sender, EventArgs e)
            {
                HttpWebRequest_BeginGetResponse instance = new HttpWebRequest_BeginGetResponse();
                instance.GetDataEvent += new HttpWebRequest_BeginGetResponse.GetDataHandle(instance_GetDataEvent);
                instance.Request();
            }        void instance_GetDataEvent(string html)
            {
                MessageBox.Show(html);
            }前面代码
    ReadCallBack(IAsyncResult asyncResult)这个方法string stringContent;
                        stringContent = myRequestState.requestData.ToString();
                        GetDataEvent(stringContent);不把数据传递给 回调函数.
    前面怎么显示出数据???
    把你代码贴出来吧.可能是我理解错你的意思。
      

  10.   

    还有,因为也刚看线程.
    委托的异步所建立的线程.在方法完成之后,应该就被.net放入回收站,等待回收吧?
    知道的说下。我不清楚。
      

  11.   

    现在的问题是,委托的异步所建立的线程.在方法完成之后并没有被回收void instance_GetDataEvent(string html)
            {
                this.textBox1.AppendText(html+"r\n");
                textBox1.SelectionStart = textBox1.Text.Length;
                textBox1.Focus();
            } 这一句是可以执行的,在ReadCallBack中有一句GetDataEvent("成功获取");调用这个方法
    还有我这里并没有用到线程池这里并没有跨线程操作,在Init方法中我加 CheckForIllegalCrossThreadCalls = false;
    来保证跨线程调用UI安全希望知道的朋友给个话出来,谢谢
      

  12.   

    要关掉多余的异步线程,最简单就设置Thread.CurrentThread.IsBackgroud = true; 
    你这里是获取网页,应该可以直接使用
      

  13.   

    Thread.CurrentThread.IsBackgroud = true; 这个试过了变成后台线程也没有用的
      

  14.   

    通过httpWebRequest获取网页内容.同时获取很多网页.异步.
    看下书的概念.做个例子不会难.不需要牛人来。自己就可以搞定.
    主动解决问题才是学习的手段.
      

  15.   

    完全关掉程序的话,Thread.CurrentThread.IsBackgroud = true;是有用的吧,好象以前也是这么写的,关注
      

  16.   

    我也遇到了这种情况,感觉是垃圾回收机制回题,我是在异步完成后,将第0代垃圾回收了
    GC.CollectionCount(0);