多线程
既然提到多线程,首先要了解什么是线程
线程:线程是程序中一个单一的顺序控制流程.在单个程序中同时运行多个线程完成不同的工作,称为多线程.
进程与线程:进程作为操作系统执行程序的基本单位,拥有应用程序的资源,进程包含线程,进程的资源被线程共享,线程不拥有资源。
昨天在博客上 看到有个这样形容多线程和单线程
他说单线程就是一个人在一张桌子上吃饭,多线程就是多个人在一张桌子上吃饭,感觉形容还很恰当
单线程:
我们只是执行一下单个线程运行5遍
/// <summary> /// 单线程 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btn_single_Click(object sender, EventArgs e) { Stopwatch sw = new Stopwatch(); sw.Start(); Console.WriteLine("当前线程的Id{0}", System.Threading.Thread.CurrentThread.ManagedThreadId); for (int i = 0; i < 5; i++) { //执行动作 Perform_action("单线程"); } sw.Stop(); Console.WriteLine("总计耗时{0}", sw.ElapsedMilliseconds); }
/// <summary> /// 执行动作 /// </summary> /// <param name="threadName"></param> public void Perform_action(string threadName) { Console.WriteLine("Perform_Action当前线程的ID{0},当前时间是{1}", System.Threading.Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:ff")); long sum = 0; for (int i = 0; i < 999999999; i++) { sum += i; } Console.WriteLine("{0},{1},当前的时间{2},当前线程的ID{3}", threadName, sum, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:ff"), System.Threading.Thread.CurrentThread.ManagedThreadId); }
执行完发现线程没有运行完,根本不能动界面,给用户带来的体验感很差,就有了多线程的到来
多线程:
/// <summary> /// 多线程 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btn_multiTread_Click(object sender, EventArgs e) { Console.WriteLine("当前的线程ID{0}", System.Threading.Thread.CurrentThread.ManagedThreadId); ThreadStart act = () => Perform_action("MutiThread"); for (int i = 0; i < 5; i++) { Thread thread = new Thread(act); thread.Start(); } Console.WriteLine("btn_multiTread_Click已经结束,可以执行其它动作"); }
使用了多线程就可以发现,我只需要执行完当前线程,就可以调用当前界面,操作别的,不用等待执行动作(Perform_action)里面的任务完成,这是多线程给我们带来的好处
线程池:
线程池是指在初始化一个多线程应用程序过程中创建一个线程集合,然后在需要执行新的任务时重用这些线程而不是新建一个线程。线程池中线程的数量通常完全取决于可用内存数量和应用程序的需求。然而,增加可用线程数量是可能的。线程池中的每个线程都有被分配一个任务,一旦任务已经完成了,线程回到池子中并等待下一次分配任务。
这里可以理解线程池就是装载线程的一个容器
线程池的作用:
线程池是为突然大量爆发的线程设计的,通过有限的几个固定线程为大量的操作服务,减少了创建和销毁线程所需的时间,从而提高效率。
如果一个线程的时间非常长,就没必要用线程池了(不是不能作长时间操作,而是不宜。),况且我们还不能控制线程池中线程的开始、挂起、和中止。
/// <summary> /// 线程池 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btn_ThreadPool_Click(object sender, EventArgs e) { Console.WriteLine("当前的线程ID{0}", System.Threading.Thread.CurrentThread.ManagedThreadId); ThreadPool.QueueUserWorkItem(t => Perform_action("ThreadPool1")); ThreadPool.QueueUserWorkItem(t => Perform_action("ThreadPool2")); ThreadPool.QueueUserWorkItem(t => Perform_action("ThreadPool3")); ThreadPool.QueueUserWorkItem(t => Perform_action("ThreadPool4")); ThreadPool.QueueUserWorkItem(t => Perform_action("ThreadPool5")); Console.WriteLine("btn_ThreadPool_Click已结束,可以执行其它操作"); }
由于线程池是静态的,我们直接点出来用
Task
.net4.5.2迎来了task异步编程的用法,这个相比较原来传统的System.Threading.Thread用起来更方便,速度效率也更高
就是工厂也是提供了静态,直接拿来调用
现在做一个小例子,随机弹出一个小组组员的名字:
实例:
1.声明一组数组(装组员名称)
//1.声明一组数组 private string[] number = { "张三","李四","王五","赵六","田七","zhaolei","saili","jieke","rousi" };
2.随机出来就利用Random获取随机出现的名字
/// <summary> /// 获取随机产生的名字 /// </summary> /// <returns></returns> public string GetNumbers() { Thread.Sleep(300); Random rd = new Random(); string txt = string.Empty; int num = rd.Next(0, 9); txt = number[num]; return txt; }
点击开始按钮,开始线程
this.btn_start.Enabled = false; isgo = true; Thread.Sleep(300); Task.Factory.StartNew(() => { while (isgo) { string txt = GetNumbers(); if (txt == null) return; if (this.InvokeRequired) { label1.BeginInvoke(new Action(() => { label1.Text = txt; })); } } });
isgo用来控制界面的able1是否停止的,true运行,false停止
上面的例子很直接的用到了task的静态方法,直接点击Task.Factory.StartNew
这个时候改动一下,需要停止的时候,开始另外一个线程,也就是加一个延迟线程ContinueWhenAll,这时候来改动代码
/// <summary> /// 开始 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btn_start_Click(object sender, EventArgs e) { this.btn_start.Enabled = false; isgo = true; Thread.Sleep(300); List<Task> taskList = new List<Task>(); TaskFactory taskfactory = new TaskFactory(); taskList.Add(taskfactory.StartNew(() => { while (isgo) { string txt = GetNumbers(); if (txt == null) return; if (this.InvokeRequired) { label1.BeginInvoke(new Action(() => { label1.Text = txt; })); } } })); taskfactory.ContinueWhenAll(taskList.ToArray(), l => { MessageBox.Show(string.Format("组员的名字是:{0}", label1.Text)); }); this.btn_stop.Enabled = true; }
这里面我用list把线程装起来了,这样加载延迟线程他就可以按顺序执行。
这里面的tasklist个人理解就是所有线程的容器,所以多个线程的话,需要使用list<task>存放一下。