5天不再惧怕多线程——第一天 尝试Thread
5天不再惧怕多线程——第一天 尝试Thread
原本准备在mongodb之后写一个lucene.net系列,不过这几天用到多线程时才发现自己对多线程的了解少之又少,仅仅停留在lock上面,
故这几天看了下线程参考手册结合自己的心得整理一下放在博客上作为自己的学习笔记。
好了,我们知道“负载”是一个很时尚,很牛X的玩意,往大处说,网站需要负载,数据库需要负载。往小处说,线程也需要负载,面对海量的
用户请求,我们的单线程肯定扛不住,那么怎么办,一定要负载,所以说多线程是我们码农必须要熟练掌握的一门技术。
在framework中给我们提供了一个Threading命名空间,下面是一个msdn上不完整的截图:
在后面的系列中我也是主要整理这几个类的使用方法和应用场景。
一:Thread的使用
我们知道这个类代表处理器线程,在Thread中有几个比较常用和重要的方法。
<1> sleep: 这个算是最简单的了。
<2> join: 这个可以让并发行处理变成串行化,什么意思呢?上代码说话最清楚。
![](/assets/blank.gif)
1 class Test 2 { 3 static void Main() 4 { 5 Thread t = new Thread(Run); 6 7 t.Start(); 8 9 //Join相当于把Run方法内嵌如此10 t.Join();11 12 //该死的t.Join(),害的我主线程必须在你执行完后才能执行。13 Console.WriteLine("我是主线程:" + Thread.CurrentThread.GetHashCode());14 }15 16 static void Run()17 {18 //等待5s19 Thread.Sleep(5000);20 21 Console.WriteLine("我是线程:" + Thread.CurrentThread.GetHashCode());22 }23 }
![](/assets/blank.gif)
<3> Interrupt和Abort:这两个关键字都是用来强制终止线程,不过两者还是有区别的。
① Interrupt: 抛出的是 ThreadInterruptedException 异常。
Abort: 抛出的是 ThreadAbortException 异常。
② Interrupt:如果终止工作线程,只能管到一次,工作线程的下一次sleep就管不到了,相当于一个
contine操作。
Abort:这个就是相当于一个break操作,工作线程彻底死掉。
Interrupt:
![](/assets/blank.gif)
1 namespace Test 2 { 3 class Program 4 { 5 static void Main(string[] args) 6 { 7 Thread t = new Thread(new ThreadStart(Run)); 8 9 t.Start();10 11 //阻止动作12 t.Interrupt();13 14 Console.Read();15 }16 17 static void Run()18 {19 for (int i = 1; i <= 3; i++)20 {21 Stopwatch watch = new Stopwatch();22 23 try24 {25 watch.Start();26 Thread.Sleep(2000);27 watch.Stop();28 29 Console.WriteLine("第{0}延迟执行:{1}ms", i, watch.ElapsedMilliseconds);30 }31 catch (ThreadInterruptedException e)32 {33 Console.WriteLine("第{0}延迟执行:{1}ms,不过抛出异常", i, watch.ElapsedMilliseconds);34 }35 }36 }37 }38 }
![](/assets/blank.gif)
Abort: 工作线程直接退出,不带走一片云彩。
![](/assets/blank.gif)
1 namespace Test 2 { 3 class Program 4 { 5 static void Main(string[] args) 6 { 7 Thread t = new Thread(new ThreadStart(Run)); 8 9 t.Start();10 11 Thread.Sleep(100);12 13 //阻止动作14 t.Abort();15 16 Console.Read();17 }18 19 static void Run()20 {21 for (int i = 1; i <= 3; i++)22 {23 Stopwatch watch = new Stopwatch();24 25 try26 {27 watch.Start();28 Thread.Sleep(2000);29 watch.Stop();30 31 Console.WriteLine("第{0}延迟执行:{1}ms", i, watch.ElapsedMilliseconds);32 }33 catch (ThreadAbortException e)34 {35 Console.WriteLine("第{0}延迟执行:{1}ms,不过抛出异常", i, watch.ElapsedMilliseconds);36 }37 }38 }39 }40 }
![](/assets/blank.gif)
二:线程使用场景
可能线程的使用有点类似wcf,做一些耗时但不很及时的需求,比如可以开线程下图片,连接数据库等等,当然线程可以用来做负载,这里就做
一个小demo,找一个美女网站,面对如此多的图片,一个线程真的吃不消啊,
看了下网站主体上有4个tab页,那么我们就开4个线程来负载
![](/assets/blank.gif)
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 string[] str = { "model", "sexy", "belle", "stars" }; 6 7 for (int url = 0; url < str.Length; url++) 8 { 9 Thread thread = new Thread(DownLoad); 10 11 thread.Start(str[url]); 12 } 13 Console.Read(); 14 } 15 16 public static void DownLoad(object category) 17 { 18 string url = string.Empty; 19 20 for (int purl = 9014; purl > 10; purl--) 21 { 22 for (int pageSize = 0; pageSize < 20; pageSize++) 23 { 24 try 25 { 26 if (pageSize == 0) 27 url = "http://www.mm8mm8.com/" + category + "/" + purl + ".html"; 28 else 29 url = "http://www.mm8mm8.com/" + category + "/" + purl + "_" + pageSize + ".html"; 30 31 //创建http链接 32 var request = (HttpWebRequest)WebRequest.Create(url); 33 34 request.Timeout = 1000 * 5; //5s过期 35 36 var response = (HttpWebResponse)request.GetResponse(); 37 38 Stream stream = response.GetResponseStream(); 39 40 StreamReader sr = new StreamReader(stream); 41 42 string content = sr.ReadToEnd(); 43 44 var list = GetHtmlImageUrlList(content); 45 46 WebClient client = new WebClient(); 47 48 string[] directory = { @"C:\MM\", @"D:\MM\", @"E:\MM\", @"F:\MM\" }; 49 50 var directoryName = directory[new Random().Next(0, directory.Length)]; 51 52 if (!Directory.Exists(directoryName)) 53 Directory.CreateDirectory(directoryName); 54 55 var fileName = string.Empty; 56 57 if (list.Count == 0) 58 { 59 Console.WriteLine("时间:" + DateTime.Now + " 当前网址:" + url + " 未发现图片"); 60 break; 61 } 62 63 try 64 { 65 66 fileName = category + "_" + purl + "_" + (pageSize + 1) + ".jpg"; 67 68 var localFile = directoryName + fileName; 69 70 var imageRequest = (HttpWebRequest)WebRequest.Create(list[0]); 71 72 imageRequest.Timeout = 1000 * 5; //5s 超时 73 74 var imageResponse = (HttpWebResponse)imageRequest.GetResponse(); 75 76 var s = imageResponse.GetResponseStream(); 77 78 Image image = Image.FromStream(s); 79 80 image.Save(localFile); 81 82 image.Dispose(); 83 84 Console.WriteLine("时间:" + DateTime.Now + " 图片:" + fileName + " 已经下载 存入磁盘位置:" + localFile); 85 86 } 87 catch (Exception e) 88 { 89 Console.WriteLine("时间:" + DateTime.Now + " 当前图片:" + fileName + " 错误信息:" + e.Message); 90 continue; 91 } 92 } 93 catch (Exception ex) 94 { 95 Console.WriteLine("时间:" + DateTime.Now + " 当前网址:" + url + " 错误信息:" + ex.Message); 96 } 97 } 98 } 99 }100 101 /// <summary> 102 /// 取得HTML中所有图片的 URL。 103 /// </summary> 104 /// <param name="sHtmlText">HTML代码</param> 105 /// <returns>图片的URL列表</returns> 106 public static List<string> GetHtmlImageUrlList(string sHtmlText)107 {108 // 定义正则表达式用来匹配 img 标签 109 Regex regImg = new Regex(@"<img\b[^<>]*?\bsrc[\s\t\r\n]*=[\s\t\r\n]*[""']?[\s\t\r\n]*(?<imgUrl>[^\s\t\r\n""'<>]*)[^<>]*?/?[\s\t\r\n]*>", RegexOptions.IgnoreCase);110 111 // 搜索匹配的字符串 112 MatchCollection matches = regImg.Matches(sHtmlText);113 114 List<string> sUrlList = new List<string>();115 116 // 取得匹配项列表 117 foreach (Match match in matches)118 sUrlList.Add(match.Groups["imgUrl"].Value);119 return sUrlList;120 }121 }
![](/assets/blank.gif)
三:对线程的一些思考
我们知道线程的优点还是比较多的,每个线程都需要默认的堆栈空间,所以说线程数受到内存空间大小的限制,如果线程数开的太多
反而适得其反,进程被分配的时间片会被线程分的更细,也就导致了处理器需要更频繁的在线程之间来回切换。
————————————————————————————————————————————————————————————
————————————————————————————————————————————————————————————
5天不再惧怕多线程——第一天 尝试Thread相关推荐
- 5天不再惧怕多线程——第三天 互斥体
5天不再惧怕多线程--第三天 互斥体 没想到我的前两篇文章还挺受欢迎的,谢谢大家,今天整理下Mutex的使用. 一:Mutex 首先看下MSDN对它的解释: 不错,出现了一个亮点,可用于"进 ...
- 5天不再惧怕多线程——第二天 锁机制
5天不再惧怕多线程--第二天 锁机制 当多个线程在并发的时候,难免会碰到相互冲突的事情,比如最经典的ATM机的问题,并发不可怕,可怕的是我们没有能力控制. 线程以我的理解可以分为三种 ① 锁. ② 互 ...
- WCHAR我不再惧怕了 - 随感而发 - C++博客
WCHAR我不再惧怕了 - 随感而发 - C++博客 WCHAR我不再惧怕了 - 随感而发 - C++博客 WCHAR我不再惧怕了 宽字符已经困扰我很久了,以前我都是设置项目的属性把它改为多字节,不用 ...
- WCHAR我不再惧怕了
转自http://www.cppblog.com/shongbee2/archive/2009/04/28/81349.html 补充:WideCharToMultiByte转换为char*之后,是G ...
- qq分享提示设备未授权_QQ帐号已经可以注销了,过去几天,第一批尝试的人已经放弃了!...
3月13日,Android版手机QQ更新至7.9.9版本,此前处于内测的注销功能正式上线,你会注销QQ吗?第一批尝试的人却-- 昨日起,QQ注销功能正式上线,用户可通过"设置"→& ...
- C#多线程编程介绍——使用thread、threadpool、timer
C#多线程编程介绍--使用thread.threadpool.timer 在system.threading 命名空间提供一些使得能进行多线程编程的类和接口,其中线程的创建有以下三种方法:thread ...
- iOS开发-多线程编程技术(Thread、Cocoa operations、GCD)
简介 在软件开发中,多线程编程技术被广泛应用,相信多线程任务对我们来说已经不再陌生了.有了多线程技术,我们可以同做多个事情,而不是一个一个任务地进行.比如:前端和后台作交互.大任务(需要耗费一定的时间 ...
- 多线程并发 (二) 了解 Thread
章节: 多线程并发 (一) 了解 Java 虚拟机 - JVM 多线程并发 (二) 了解 Thread 多线程并发 (三) 锁 synchronized.volatile 多线程并发 (四) 了解原子 ...
- Java多线程-线程的创建(Thread类的基本使用)
文章目录 一. 线程和Thread类 1. 线程和Thread类 1.1 Thread类的构造方法 1.2 启用线程的相关方法 2. 创建第一个Java多线程程序 3. 使用Runnable对象创建线 ...
最新文章
- 计算机管理员身份有哪些优点,重装系统有什么好处?有哪些理由值得让电脑重装系统?...
- 关于Puppet不得不说的故事
- C#中获取当前应用程序的路径及环境变量
- 存储库访问被拒绝。通过部署密钥进行访问是只读的
- Mac环境PHP踩过的“坑” (一)函数重载
- 【Groovy】闭包 Closure ( 闭包调用 | 闭包默认参数 it | 代码示例 )
- mysql5.6.27_Centos上安装Mysql5.6.27多实例
- webservice 返回对象 java_JAVA 调用webservice不同返回值类型的方法
- Mysql当前模式让不记录日志_MySQL日志binlog的三种模式
- C# winForm 定时访问PHP页面小工具
- 博客系统知多少:揭秘那些不为人知的学问(二)
- 《C++语言入门经典》一第3章 重要的逻辑工具——判断与循环 3.1 条件判断...
- Python大数据依赖包安装
- Eclipse里做JBPM工作流gpd.xml中文乱码问题解决
- jersey2 java_无废话Jersey构建RESTful服务之WebService系统教程 --2 [JAVA对象转换成XML输出]...
- js ajax 跨域上传文件,使用 Javascript 实现跨域上传文件到存储
- 在linux系统上搭建测试环境
- MaxCompute SQL引用第三方Base64JAR实现编解码
- MATHTYPE安装出现问题:无法打开要写入的文件;MathType打开word时“安全警告,宏已被禁用”;mathtype与AXmath不能同时使用
- CheckListBox的实现方式分析