近段时间想自己做个多线程的抓取程序经过研究抓取问题已经解决,现在想实现多个任务同时抓取,主要是为了提高抓取效率。本人对C#多线程没有怎么接触过,所以还请各位指点。具体实现结果:1、任务列表里有多个任务(如:xxx.com/0001.html,xxx.com/9999.html)2、要求同时创建多个线程(如:5个),每个线程抓取一个网页地址,如下对应关系:Thread1  --  xxx.com/0001.html
Thread2  --  xxx.com/0002.html
Thread3  --  xxx.com/0003.html
Thread4  --  xxx.com/0004.html
Thread5  --  xxx.com/0005.html当线程1-5中某个线程抓取完毕,自动创建一个新的线程对应地址 xxx.com/0006.html可能涉及到的问题:获取活动线程数,获取状态为未抓取的临近目录 希望各位能够帮忙解答一下,如能给出类似代码最佳,否则给出相应资料也可。感激不尽

解决方案 »

  1.   

    你可以一开始就开辟10-20个线程的样子,不停的做循环。
    然后在程序启动时你应该能得到一个网站所有的页,把所有的页的名字以及状态还有时间什么的封装成一个类,然后放到一个线程安全的集合,就是读和更新用lock锁住。
    每个线程抓完一个页面就更新它对应与集合里的item的状态为已抓取,完成时间等。然后再遍历这个集合找到item的状态为未抓取的item,把状态变为正在抓取,然后取出页面名字继续抓取,如此循环就可以了。
      

  2.   

    WebClient支持异步下载
    WebClient client = new WebClient();
    client.DownloadDataAsync("http://xxx.com/0001.html ");  
    client.DownloadFileCompleted += (client_DownloadFileCompleted);
    client.DownloadProgressChanged += (client_DownloadProgressChanged);void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
    {
                
    }void client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
    {
                
    }你可以自己放个List<WebClient>保存下载的实例个数,在DownloadFileCompleted事件里移除WebClient实例实现上应该比较简单
      

  3.   

    函数弄错了,不好意思,下载文件是:client.DownloadFileAsync()
      

  4.   

    http://blog.chinahr.com/blog/hankwen/post/83503
    不知道对你有帮助不
      

  5.   

    我目前的代码是
                    HttpWebRequest request = WebRequest.Create(new Uri("xxxx.html")) as HttpWebRequest;                request.CookieContainer = CookieContainer;
                    request.Method = "get";
                    request.KeepAlive = false;                HttpWebResponse response;
                    try
                    {
                        response = request.GetResponse() as HttpWebResponse;
                    }
                    catch (System.Net.WebException ex)
                    {
                        this.SetValue(this.progressBar1.Value + 1);
                        continue;
                    }
                    Stream stream;
                    stream = response.GetResponseStream();
                    StreamReader reader = new System.IO.StreamReader(stream, Encoding.Default);
                    html = reader.ReadToEnd();
      

  6.   

    我的方案不行吗?
    其实就是先遍历你要下载的网站的所有下载页面,整一张任务列表,任务有状态等属性,然后开那么10来个线程根据状态去任务列表里获取未处理的任务处理,处理完了更新当前任务状态又去拿任务,如果循环而已。
    至于线程控制,最简单的莫过于线程在那里循环不停干活了,如果你想控制线程的开停,while的条件是一个bool变量,要停的话把这个变量变成false就可以了,重新开始就赋值为true再起线程就ok了。
      

  7.   

    使用Queue<T>来存放任务列表。记住出队入队的时候先lock(queue)实践一下。
      

  8.   

    下午研究了一下,可以考虑用线程池:Threadpool        static void Main(string[] args)
            {            //设置最大活动线程的条目数
                ThreadPool.SetMaxThreads(5, 5);
                for (int i = 0; i < 10; i++)
                {
                    ThreadPool.UnsafeQueueUserWorkItem(new WaitCallback(DoSomething), i);
                }
                
                Console.Read();
            }
            static void DoSomething(object obj)
            {
                int i = 0;
                int j = (int)obj;
                while (i < 20)
                {
                    Console.WriteLine("thread {0},{1}", j, i);
                    i++;
                    Thread.Sleep(200);
                }
            }
    输出结果:
    thread 1,0
    thread 0,0
    thread 0,1
    thread 1,1
    thread 1,2
    thread 0,2
    thread 0,3
    thread 1,3
    thread 0,4
    thread 1,4
    thread 2,0
    thread 0,5
    thread 1,5
    thread 2,1
    thread 0,6
    thread 1,6
    thread 2,2
    thread 0,7
    thread 1,7
    thread 2,3
    thread 1,8
    thread 0,8
    thread 2,4
    thread 0,9
    thread 1,9
    thread 2,5
    thread 0,10
    thread 1,10
    thread 2,6
    thread 0,11
    thread 1,11
    thread 2,7
    thread 0,12
    thread 1,12
    thread 2,8
    thread 0,13
    thread 1,13
    thread 2,9
    thread 0,14
    thread 1,14
    thread 2,10
    thread 0,15
    thread 1,15
    thread 2,11
    thread 0,16
    thread 1,16
    thread 2,12
    thread 0,17
    thread 1,17
    thread 2,13
    thread 0,18
    thread 1,18
    thread 2,14
    thread 0,19
    thread 1,19
    thread 2,15
    thread 3,0
    thread 4,0
    thread 2,16
    thread 3,1
    thread 4,1
    thread 2,17
    thread 3,2
    thread 4,2
    thread 2,18
    thread 3,3
    thread 4,3
    thread 2,19
    thread 3,4
    thread 4,4
    thread 5,0
    thread 3,5
    thread 4,5
    thread 5,1
    thread 3,6
    thread 4,6
    thread 5,2
    thread 3,7
    thread 4,7
    thread 5,3
    thread 3,8
    thread 4,8
    thread 5,4
    thread 3,9
    thread 4,9
    thread 5,5
    thread 3,10
    thread 4,10
    thread 5,6
    thread 3,11
    thread 4,11
    thread 5,7
    thread 3,12
    thread 4,12
    thread 5,8
    thread 3,13
    thread 4,13
    thread 5,9
    thread 3,14
    thread 4,14
    thread 5,10
    thread 3,15
    thread 4,15
    thread 5,11
    thread 3,16
    thread 4,16
    thread 5,12
    thread 3,17
    thread 4,17
    thread 5,13
    thread 3,18
    thread 4,18
    thread 5,14
    thread 3,19
    thread 4,19
    thread 5,15
    thread 6,0
    thread 7,0
    thread 5,16
    thread 6,1
    thread 7,1
    thread 5,17
    thread 6,2
    thread 7,2
    thread 5,18
    thread 6,3
    thread 7,3
    thread 5,19
    thread 6,4
    thread 7,4
    thread 8,0
    thread 6,5
    thread 7,5
    thread 8,1
    thread 6,6
    thread 7,6
    thread 8,2
    thread 6,7
    thread 7,7
    thread 8,3
    thread 6,8
    thread 7,8
    thread 8,4
    thread 6,9
    thread 7,9
    thread 8,5
    thread 6,10
    thread 7,10
    thread 8,6
    thread 6,11
    thread 7,11
    thread 8,7
    thread 6,12
    thread 7,12
    thread 8,8
    thread 6,13
    thread 7,13
    thread 8,9
    thread 6,14
    thread 7,14
    thread 7,15
    thread 8,10
    thread 6,15
    thread 6,16
    thread 8,11
    thread 7,16
    thread 7,17
    thread 8,12
    thread 6,17
    thread 8,13
    thread 6,18
    thread 7,18
    thread 8,14
    thread 6,19
    thread 7,19
    thread 8,15
    thread 9,0
    thread 8,16
    thread 9,1
    thread 8,17
    thread 9,2
    thread 8,18
    thread 9,3
    thread 8,19
    thread 9,4
    thread 9,5
    thread 9,6
    thread 9,7
    thread 9,8
    thread 9,9
    thread 9,10
    thread 9,11
    thread 9,12
    thread 9,13
    thread 9,14
    thread 9,15
    thread 9,16
    thread 9,17
    thread 9,18
    thread 9,19
      

  9.   

    class Program
    {
    public class DownloadInfo
    {
    public string Url;
    public int Status;//0-未下载,1-下载中,2-已下载
    public DateTime DownloadDateTime;public DownloadInfo(string url)
    {
    Url = url;
    }
    }
    object _locker = new object();
    private List<DownloadInfo> _downloadInfoList = new List<DownloadInfo>();
    DownloadInfo GetDownloadInfo(ref int currentIndex)
    {
    lock(_locker)
    {
    for(int i = currentIndex + 1;i < _downloadInfoList.Count; i ++)
    {
       if(download.Status == 0)
    {
    currentIndex = i;
    download.Status = 1;
    return download;
    }
    }
    return null;
    }
    }
    public void Init(string[] allofurlInWebSite)
    {
    froeach(string url in allofurlInWebSite)
    {
    _downloadInfoList.Add(new DownloadInfo(url));
    }
    }public void Finished()
    {
    if(_threadSwitch)
    {
    return;
    }
    _downloadInfoList.Clear();
    for(int i  = 0; i < _threads.Length ; i ++)
    {
    _threads[i] = null;
    }
    _threads = null;
    }Thread[] _threads = null;
    bool _threadSwitch = false;
    publc void Start()
    {
    if(_threads != null)
    {
    return;
    }
    threadSwitch  = true;
    _threads = new Thread[15];
    for(int i  = 0; i < _threads.Length ; i ++)
    {
    _threads[i] = new Thread(Run);
    _threads[i].Start();
    }
    }public void Stop()
    {
    if(_threads == null)
    {
    return;
    }
    _threadSwitch = false;
    Thread.Sleep(1000);
    for(int i  = 0; i < _threads.Length ; i ++)
    {
    _threads[i] = null;
    }
    }_threads = null;
    }
    public void Run()
    {
    int index = 0;
    while(_threadSwitch)
    {
    DownloadInfo downloadInfo = GetDownloadInfo(ref index);
    //根据downloadInfo的url开始下载
    ...downloadInfo.Status = 2;
    }
    }
    }在回复框里写的,可能有些错误。
      

  10.   

    先调用Init,初始化任务队列,然后调用Start开始下载,少写了一个东西,应该各线程发现任务队列都下载完了,应该通知调用方,这样再调用Stop,再调用Finished,一个网站的下载完毕。
    下载另外一个网站重新调用Init,或者一开始把所有需要下载的列表传进去也行。如果需要其他功能,你自己扩展就可以了,思路大致是这样的
      

  11.   

    public void Run() 

    int index = 0; 
    while(_threadSwitch) 

    DownloadInfo downloadInfo = GetDownloadInfo(ref index); 
    if(downloadInfo == null)
    {
    MessageBox.Show("已经没有可下载的任务了");
    break;
    }
    //根据downloadInfo的url开始下载 
    ... downloadInfo.Status = 2; 

      

  12.   


    DownloadInfo GetDownloadInfo(ref int currentIndex) 

    lock(_locker) 

    for(int i = currentIndex;i < _downloadInfoList.Count; i ++) 

      if(download.Status == 0) 

    currentIndex = i; 
    download.Status = 1; 
    return download; 


    return null; 

    } public void Run() 

    int index = 0; 
    while(_threadSwitch) 

    DownloadInfo downloadInfo = GetDownloadInfo(ref index); 
    if(downloadInfo == null) 

    //此处要加上,防止漏掉了任务,从新从队列里搜索一遍
    index = 0;
    downloadInfo = GetDownloadInfo(ref index);
    if(downloadInfo == null)
    {
    MessageBox.Show("已经没有可下载的任务了"); 
    break; 
    }

    //根据downloadInfo的url开始下载 
    ... downloadInfo.Status = 2; 
    } 这两个方法改下,有点问题。
      

  13.   

    DownloadInfo GetDownloadInfo(ref int currentIndex) 

    lock(_locker) 

    for(int i = currentIndex;i < _downloadInfoList.Count; i ++) 

    DownloadInfo download = _downloadInfoList[i];
      if(download.Status == 0) 

    currentIndex = i; 
    download.Status = 1; 
    return download; 


    return null; 

    } 呵呵,这样应该就对了