多线程应用
多线程应用很广泛,简单总结了一下:
1)不阻断主线程,实现即时响应,由后台线程完成特定操作
2)多个线程,完成同类任务,提高并发性能
3)一个任务有多个独立的步骤,多个线程并发执行各子任务,提高任务处理效率
下面我们通过几个小例子做简单介绍。
1、进度条
分析:页面动态刷新,主页面正常可操作。我们通过后台线程来实现进度条。
首先,创建Winform页面,然后拖入进度条控件,将页面的代码改为以下代码即可。
这里只是个简单的例子,其实我们可以做的更好,将进度条封装为一个自定义控件,设计为一个通用好看的进度条。这里只讲技术和方向,大家可以自己研究研究。
相关代码:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Threading; namespace ProgressBarSample { //定义委托,异步调用 delegate void ShowProgressDelegate(int totalStep, int currentStep); public partial class Form1 : Form { public Form1() { InitializeComponent(); } /// <summary> /// /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnStart_Click(object sender, EventArgs e) { ParameterizedThreadStart start = new ParameterizedThreadStart(SetProgress); Thread progressThread = new Thread(start); progressThread.IsBackground = true;//标记为后台进程,在窗口退出时,正常退出 progressThread.Start(); } /// <summary> /// 设置当前进度 /// </summary> /// <param name="state"></param> void SetProgress(object state) { for (int i = 1; i <= 100; i++) { Thread.Sleep(200); object[] objs = new object[] { 100, i }; //异步调用 this.Invoke(new ShowProgressDelegate(ShowProgress), objs); } } /// <summary> /// 刷新进度条 /// </summary> /// <param name="totalStep"></param> /// <param name="currentStep"></param> void ShowProgress(int totalStep, int currentStep) { this.progressBar1.Maximum = totalStep; this.progressBar1.Value = currentStep; this.lbCurrent.Text = this.progressBar1.Value * 100 / progressBar1.Maximum + "%"; } } }
2、网络扒虫
经常遇到这样的场景,通过扒虫程序,去互联网获取所需资源。其实搜索引擎的一个重要组成部分就是扒虫。但是,往往扒虫程序比较费时,这时就需要多线程帮忙。
这里写一个简单的扒虫程序,说明下原理。
案例:通过网络连接,获取网络相关信息。
扒虫对象:
using System; using System.Net; namespace Reptile { public class NetReptile { /// <summary> /// /// </summary> public string Url { get; set; } /// <summary> /// /// </summary> /// <param name="url"></param> public NetReptile(string url) { this.Url = url; } /// <summary> /// /// </summary> /// <returns></returns> public string GetContent() { WebClient client = new WebClient(); return client.DownloadString(new Uri(this.Url)); } } }
抓到内容后,需要解析,提取我们需要的内容,这里以抓取网页的标题为例。解析器代码:
using System; using System.Text; using System.Text.RegularExpressions; namespace Reptile { /// <summary> /// HTML解析器 /// </summary> public class HtmlAnalyzer { /// <summary> /// 构造函数 /// </summary> public HtmlAnalyzer() { } /// <summary> /// 获取标题 /// </summary> /// <param name="html"></param> /// <returns></returns> public string GetTitle(string html) { Regex regext = new Regex("(?<=<title>).*?(?=</title>)"); Match m = regext.Match(html); if (m != null) { return m.ToString(); } return null; } } }
使用多线程创建扒虫,抓取数据:
/// <summary> /// 多线程处理 /// </summary> private void MultiThread() { string urls = tbUrl.Text; string[] separater = { "\r\n" }; string[] urlList = urls.Split(separater, StringSplitOptions.RemoveEmptyEntries); int i = 1; foreach (var url in urlList) { Thread thread = new Thread(new ParameterizedThreadStart(Snap)); thread.Name = "Thread" + i.ToString(); thread.Start(url); i++; } //RefreshData(); } /// <summary> /// 抓取数据 /// </summary> /// <param name="state"></param> private void Snap(object state) { string url = state as string; NetReptile reptile = new NetReptile(url); string html = reptile.GetContent(); if (!string.IsNullOrEmpty(html)) { HtmlAnalyzer analyzer = new HtmlAnalyzer(); string title = analyzer.GetTitle(html); Thread.Sleep(2000); this.Invoke(new AddItemDelegate(this.AddItem),title); } } /// <summary> /// /// </summary> /// <param name="item"></param> private void AddItem(string item) { this.listData.Items.Add(item); }
全部源码:https://files.cnblogs.com/yank/Reptile.rar
其他:
多线程应用还有很多,比如:文件上传和下载、异步加载、Web请求、压力测试、流水线技术等等。后续我们还会将一些典型案例更新在这里。