首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > .NET > C# >

Thread的一个简单有关问题,有答案马上结帖

2012-02-14 
Thread的一个简单问题,有答案马上结帖我在做一个数据采集的程序,当同时在多个网站采集数据时,如果有采集网

Thread的一个简单问题,有答案马上结帖
我在做一个数据采集的程序,当同时在多个网站采集数据时,如果有采集网站出现故障打不开或打开得非常慢时,就会导致异常使程序无法响应。

我的想法是当部分网站采集不了时,并不影响程序的运行,其他的采集任务还是能继续。

觉得只有用多线程处理,但之前没有应用过,所以请大家给个示例代码,谢谢!~

主要代码如下:

              //采集
                private   void   getInfo(string   url,Encoding   coding)
                {
                        //...
                        HttpWebRequest   request   =   (HttpWebRequest)WebRequest.Create(url);
                        request.Timeout   =   5000;
                        try
                        {

                                WebResponse   response   =   request.GetResponse();
                                Stream   strm   =   response.GetResponseStream();
                                StreamReader   sr   =   new   StreamReader(strm,   coding);
                                collectInfo   =   sr.ReadToEnd();
                                strm.Close();
                                sr.Close();
                        }
                        catch(Exception   ex)
                        {
                                MessageBox.Show(ex.Message);
                        }
                        //...
                }

//主程序里调用
                private   void   button1_Click(object   sender,   EventArgs   e)
                {
                        //...
                        CollectionInfo   coll   =   new   CollectionInfo();
                       
                        coll.getInfo( "http://www.site1.com/index.html ",Encoding.UTF8);
                       
                        coll.getInfo( "http://www.site2.com/index.aspx ",Encoding.UTF8);


                   
                        coll.getInfo( "http://www.site3.com/index.php ",Encoding.UTF8);
   
                        //...
                }

当我点采集的时候,遇到连接不上的网页,就会出错。我设置了HttpWebRequest的timeout也没用。

请大家看看如何利用多线程改一下

[解决办法]
private void run1()
{
CollectionInfo coll = new CollectionInfo();
coll.getInfo( "http://www.site1.com/index.html ",Encoding.UTF8);
}
private void run2()
{
CollectionInfo coll = new CollectionInfo();
coll.getInfo( "http://www.site2.com/index.aspx ",Encoding.UTF8);
}

private void run3()
{
CollectionInfo coll = new CollectionInfo();
coll.getInfo( "http://www.site3.com/index.php ",Encoding.UTF8);
}
private void button1_Click(object sender, EventArgs e)
{
ThreadStart ts1=new ThreadStart(run1);
Thread tr1=new Thread(ts1);
tr1.Start();
ThreadStart ts2=new ThreadStart(run2);
Thread tr2=new Thread(ts2);
tr2.Start();
ThreadStart ts3=new ThreadStart(run3);
Thread tr3=new Thread(ts3);
tr3.Start();

}
[解决办法]
提交的是个方法的名称如run3()
不能够传递参数的.

问题相关: 主线程与创建线程的交换数据
[解决办法]
说一个思路吧...

这种情况可以建一个任务队列,将你所要采集的所有URL存储在这个队列中(可以用ArrayList,或者List <string> 等等),多个线程从队列中取出任务进行抓取,当然取出一条任务后,就要将任务从队列中删除,即维护好任务队列...

在抓取过程中,如果遇到异常,捕获一下,可以将异常写到日志文件中,而不是抛出,这样就算出现异常也不会影响整个程序的运行...

有关多线程可以看看MSDN..
[解决办法]
看一这个就明白了,用类的方法作线程执行的过程.
这样就可以用类属性传值地。
分静态方法和非静态方法两种使用办法。

using System;
using System.Threading;

class Test
{
static void Main()
{
// To start a thread using a static thread procedure, use the
// class name and method name when you create the ThreadStart
// delegate. Beginning in version 2.0 of the .NET Framework,
// it is not necessary to create a delegate explicityly.
// Specify the name of the method in the Thread constructor,
// and the compiler selects the correct delegate. For example:
//
// Thread newThread = new Thread(Work.DoWork);
//
ThreadStart threadDelegate = new ThreadStart(Work.DoWork);
Thread newThread = new Thread(threadDelegate);
newThread.Start();

// To start a thread using an instance method for the thread
// procedure, use the instance variable and method name when
// you create the ThreadStart delegate. Beginning in version
// 2.0 of the .NET Framework, the explicit delegate is not
// required.
//
Work w = new Work();
w.Data = 42;
threadDelegate = new ThreadStart(w.DoMoreWork);
newThread = new Thread(threadDelegate);
newThread.Start();
}
}

class Work
{
public static void DoWork()
{
Console.WriteLine( "Static thread procedure. ");
}
public int Data;
public void DoMoreWork()
{
Console.WriteLine( "Instance thread procedure. Data={0} ", Data);


}
}

不过还是像楼上说的,把Url都存在一个队列里,把这个队列当作类的属性。
然后声明几个类的实例,调用即可。
不过要注意这几个线程的同步,用同步对象防止对队列的重入操作。
[解决办法]
private void button1_Click(object sender, EventArgs e)
{
this.Start( "http://www.site1.com/index.html ");
this.Start( "http://www.site2.com/index.aspx ");
this.Start( "http://www.site3.com/index.php ");

}

private void Start(string url)
{
myThread info=new myThread(url);
ThreadStart ts=new ThreadStart(info.Run);
Thread thread=new Thread(ts);
thread.Start();
}

public class myThread
{
private string url=string.Empty;
public myThread(string url){this.url=url;}
string Url{get{return url;}set{url=value;}}
public void Run()
{
new CollectionInfo().getInfo(url,Encoding.UTF8);
}
}

做程序要学会思考,有时可以变通。
你还可以用委托的方式更改。
[解决办法]
1.定义一个委托
public delegate void DGetInfo(string url, Encoding coding);

2.用委托的异步调用 BeginInvoke 比线程方便,而且传递参赛
用的时候
DGetInfo dinfo = new DGetInfo(getInfo);
dinfo.BeginInvoke( "http://www.site1.com/index.html ", Encoding.UTF8, null, null);

具体如何封装,就是你自己的问题了

不过这种东西没有用 MessageBox 提示错误的
如果多线程,会弹出很多的 MessageBox,写到文件或打印到命令行就可以


还有这种东西,一般是有一个队列的,
把初始参数先放到队列,然后线程去取,下载一个网页后,分析连接
在放回队列,然后再重队列里去一个 url 继续处理

如果重试验1。。n 次没有成功就放弃本次的请求
在重队列取一个新的去试验

热点排行