在C#中用多线程并不难实现。它有一个命名空间:System.Threading,提供了多线程的支持。
  

要开启一个新线程,须要以下的初始化:

ThreadStart startDownload = new ThreadStart( DownLoad );

//线程起始设置:即每个线程都执行DownLoad(),注意:DownLoad()必须为不带有参数的方法

Thread downloadThread = new Thread( startDownload ); //实例化要开启的新类

downloadThread.Start();//开启线程

由于线程起始时启动的方法不能带有参数,这就为多线程共享资源添加了麻烦。不过我们可以用类级变量(当然也可以使用其它方法,笔者以为此方法最简单易用)来解决这个问题。知道开启多线程下载的方法后,大家可能会发生几个疑问:

1.如何操纵线程的数量?

2.如何防止多线程下载同一网页?

3.如何判断线程结束?

4.如何操纵线程结束?

下面就这几个问题提出解决方法:

1.线程数量我们可以通过for循环来实现,就如同当年初学编程的打点程序一样。

譬如已知用户指定了n(它是一个int型变量)个线程吧,可以用如下方法开启五个线程。

Thread[] downloadThread;

//声名下载线程,这是C#的优势,即数组初始化时,不需要指定其长度,可以在使用时才指定。

这个声名应为类级,这样也就为其它方法控件它们提供了可能

ThreadStart startDownload = new ThreadStart( DownLoad );

//线程起始设置:即每个线程都执行DownLoad()

downloadThread = new Thread[ n ];//为线程申请资源,确定线程总数

for( int i = 0; i < n; i++ )//开启指定数量的线程数

{

downloadThread[i] = new Thread( startDownload );//指定线程起始设置

downloadThread[i].Start();//逐个开启线程

}

好了,实现控制开启线程数是不是很简单啊?

2.下面出现的一个问题:所有的线程都调用DonwLoad()方法,这样如何避免它们同时下载同一个网页呢?

这个问题也好解决,只要树立一下Url地址表,表中的每个地址只容许被一个线程申请即可。具体实现:

可以利用数据库,树立一个表,表中有四列,其中一列专门用于存储Url地址,另外两列分别存放地址对应的线程以及该地址被申请的次数,最后一列存放下载的内容。(当然,对应线程一列不是必要的)。当有线程申请后,将对应线程一列设定为当前线程编号,并将是否申请过一列设置为申请一次,这样,别的线程就无法申请该页。要是下载成功,则将内容存入内容列。要是不成功,内容列仍为空,作为是否再次下载的依据之一,如果反复不成功,则进程将于达到重试次数(对应当地址被申请的次数,用户可设)后,申请下一个Url地址。好了,这样就解决了多线程中,线程冲突。当然,去重问题也可以在C#语言内解决,只根建立一个临时文件(文本就可以),保存所有的Url地址,差对它们设置相应的属性即可,但查找效率可能不及数据库快。

3.线程结束是很难判断的,因为它总是在查找新的链接。用者认为可以假设:线程重复N次以后还是没有能申请到新的Url地址,那么可以觉得它已经下载完了所有链接。主要代码如下:

string url = "";

int times = 0;

while ( url == "" )//要是没有找到符合条件的记录,则不断地寻觅符合条件的记录

{

url = getUrl.GetAUrl( …… );//调用GetAUrl方法,试图得到一个url值

if ( url == "" )//要是没有找到

{

times ++;//尝试次数自增

continue; //进行下一次尝试

}

if ( times > N ) //要是已经尝试够了次数,则退出进程

{

downloadThread[i].Abort; //退出进程

}

else//如果没有尝试够次数

{

Times = 0; //尝试次数归零处理

}

//进行下一步针对得到的Url的处理

}

4.这个问题相对简单,因为在问题一中已经提议,将线程声名为类级数组,这样就很易于操纵。只要用一个for循环即可结束。代码如下:

for( int i = 0; i < n; i++ )//关闭指定数量n的线程数

{

downloadThread[i].Abort();//逐个关闭线程

}

好了,一个多线程的C#程序就这样完成了,在C#面前,它的实现本来如此简单。

C#动态多线程实例的更多相关文章

  1. Java反射机制可以动态修改实例中final修饰的成员变量吗?

    问题:Java反射机制可以动态修改实例中final修饰的成员变量吗? 回答是分两种情况的. 1. 当final修饰的成员变量在定义的时候就初始化了值,那么java反射机制就已经不能动态修改它的值了. ...

  2. Linux多线程实例练习 - pthread_cancel()

    Linux多线程实例练习 - pthread_cancel 1.代码 xx_pthread_cancel.c #include <pthread.h> #include <stdio ...

  3. Linux多线程实例练习 - pthread_exit() 与 pthread_join()

    Linux多线程实例练习 - pthread_exit 与 pthread_join pthread_exit():终止当前线程 void pthread_exit(void* retval); pt ...

  4. Linux多线程实例练习 - pthread_create()

    Linux多线程实例练习 pthread_create():创建一个线程 int pthread_create(pthread_t *tidp, const pthread_attr_t *attr, ...

  5. Java多线程-实例解析

    Java多线程实例 3种实现方法Java中的多线程有三种实现方式:1.继承Thread类,重写run方法.Thread本质上也是一个实现了Runnable的实例,他代表一个线程的实例,并且启动线程的唯 ...

  6. Java Tread多线程(0)一个简单的多线程实例

    作者 : 卿笃军 原文地址:http://blog.csdn.net/qingdujun/article/details/39341887 本文演示,一个简单的多线程实例,并简单分析一下线程. 编程多 ...

  7. 【原创】Kafka Consumer多线程实例续篇

    在上一篇<Kafka Consumer多线程实例>中我们讨论了KafkaConsumer多线程的两种写法:多KafkaConsumer多线程以及单KafkaConsumer多线程.在第二种 ...

  8. JAVA之旅(十二)——Thread,run和start的特点,线程运行状态,获取线程对象和名称,多线程实例演示,使用Runnable接口

    JAVA之旅(十二)--Thread,run和start的特点,线程运行状态,获取线程对象和名称,多线程实例演示,使用Runnable接口 开始挑战一些难度了,线程和I/O方面的操作了,继续坚持 一. ...

  9. Qt5.9一个简单的多线程实例(类QThread)(第一种方法)

    Qt开启多线程,主要用到类QThread.有两种方法,第一种用一个类继承QThread,然后重新改写虚函数run().当要开启新线程时,只需要实例该类,然后调用函数start(),就可以开启一条多线程 ...

随机推荐

  1. Android数据库之SQLite数据库

    Android数据库之SQLite数据库 导出查看数据库文件 在android中,为某个应用程序创建的数据库,只有它可以访问,其它应用程序是不能访问的,数据库位于Android设备/data/data ...

  2. PHP使用COM 获取RTF内容

    1. 需要在APP服务器上安装Office 2. 可能需要创建文件夹:Desktop C:\Windows\SysWOW64\config\systemprofile\Desktop 3. 可能需要设 ...

  3. Python的functools.reduce用法

    python 3.0以后, reduce已经不在built-in function里了, 要用它就得from functools import reduce. reduce的用法 reduce(fun ...

  4. BeanDefinition的载入和解析

    1.在完成对代表BeanDefinition的Resource定位的分析后,下面来了解整个BeanDefinition信息的载入过程. 2.对IoC容器来说,这个载入过程,相当于把定义的BeanDef ...

  5. (转)为首次部署MongoDB做好准备:容量计划和监控

    如果你已经完成了自己新的MongoDB应用程序的开发,并且现在正准备将它部署进产品中,那么你和你的运营团队需要讨论一些关键的问题: 最佳部署实践是什么? 为了确保应用程序满足它所必须的服务层次我们需要 ...

  6. 原生js实现addClass,removeClass,hasClass方法

    function hasClass(elem, cls) { cls = cls || ''; if (cls.replace(/\s/g, '').length == 0) return false ...

  7. 【风马一族_Python】 决策树

    <机器学习实战>第三章 决策树 ------------------------------------- #1 trees.py 计算给定数据集的香农熵 ---------------- ...

  8. 【风马一族_Android】Android 前端内容1

    Android 前端内容 4.1 View 类概述 4.1.1 关于 View //类型说明 view(视图)指的是用户界面组件的基本构建基块.一个视图占据屏幕上的矩形区域,负责绘图和事件处理.视图是 ...

  9. ADO.NET笔记——存储二进制大对象(BLOB)

    相关知识 上传二进制大对象(Binary Large Object)(如图片.视频等)的基本编程步骤是: 在数据库中使用varbinary(MAX).varchar(MAX)或者nvarchar(MA ...

  10. Linux man 用法小结(Linux指令学习笔记)

    今天买了一本<<Linux命令行与shell脚本编程大全>>,想利用暑假放假的时间系统的学习一下 Linux的shell脚本.今天看了一下书,才发现我之前学习,把Linux s ...