C#进阶2-多线程
文章目录
- C#进阶2-多线程
- 多线程初体验
- 等待
- AsyncWaitHandle
- IsCompleted,EndInvoke
- 其他本线程类
- Task
- 操作
- 并发问题
多线程初体验
它允许程序在同一时间执行多个任务,从而提高程序的性能和响应速度
public Form1(){InitializeComponent();}private void button1_Click(object sender, EventArgs e){}//异步private void button2_Click(object sender, EventArgs e){// 使用 Action 委托,一个参数的委托Action<string> action = DoSomething;//定义一个回调方法,当异步的方法调用完,才执行回调AsyncCallback calMt = new AsyncCallback(ia=> Console.WriteLine("你好"));action.BeginInvoke("btn2 method",calMt,null);//异步调用action("Button 2 Clicked");//调用委托方法action.Invoke("Button 2 Clicked");}private void DoSomething(string message){// 处理传入的字符串Console.WriteLine(message);}
值得注意的是action调用完回调异步后返回值的类型还是AsyncCallback。从这可以发现异步回调的原理,在执行异步方法后,返回回调函数,然后再调用回调函数。
等待
当我们需要异步方法执行完之后,再去执行最后总的内容,这时候就需要等待了
AsyncWaitHandle
- 可以延迟等待
// 使用 Action 委托,一个参数的委托Action<string> action = DoSomething;//定义一个回调方法,当异步的方法调用完,才执行回调AsyncCallback calMt = new AsyncCallback(ia=> Console.WriteLine("你好"));var acRe = action.BeginInvoke("异步方法1",calMt,null);//异步调用action("主线程方法1");//调用委托方法action.Invoke("主线程方法2");//acRe.AsyncWaitHandle.WaitOne();//等待异步执行完acRe.AsyncWaitHandle.WaitOne(1000);//等待1s,不管执行完与否,我都不等待了Console.WriteLine("全部任务执行完毕");
IsCompleted,EndInvoke
- while (!acRe.IsCompleted)//判断异步方法是否执行完毕
- EndInvoke:方法用于获取异步调用的结果并确保调用完成
// 使用 Action 委托,一个参数的委托Action<string> action = DoSomething;//定义一个回调方法,当异步的方法调用完,才执行回调AsyncCallback calMt = new AsyncCallback(ia=> Console.WriteLine("异步执行后完毕"));var acRe = action.BeginInvoke("异步方法1",calMt,null);//异步调用action.EndInvoke(acRe);action("主线程方法1");//调用委托方法action.Invoke("主线程方法2");Console.WriteLine("全部任务执行完毕");
其他本线程类
- Thread
- Task
- Threadpool
- Parallel
Task
Task是3.0提出来的基于TheadPool来实现的主流处理多线程的方式
操作
简单介绍一下,其他api可自行查询
- 几种执行方式,参数都是委托方法
Console.WriteLine($"主线程start=》{Thread.CurrentThread.ManagedThreadId.ToString("00")}");//1.操作//1.1 runTask.Run(() => {Console.WriteLine($"我是多线程1=》{Thread.CurrentThread.ManagedThreadId.ToString("00")}");});//1.2 factoryvar ft = Task.Factory;ft.StartNew(() => {Console.WriteLine($"我是多线程2=》{Thread.CurrentThread.ManagedThreadId.ToString("00")}");});//1.3 startTask t1 = new Task(()=>this.DoSomething("我是多线程2"));t1.Start();Console.WriteLine($"主线程end=》{Thread.CurrentThread.ManagedThreadId.ToString("00")}");
- 等待多线程执行完毕(主线程阻塞等待,卡UI)
List<Task> taskList = new List<Task>();//1.3 startTask t1 = new Task(()=>this.DoSomething("我是多线程2"));t1.Start();....t2,t3.....//等待taskList.Add(t1);taskList.Add(t2);taskList.Add(t3);Task.WaitAll(taskList.ToArray());
- 不卡界面使用,主线程不阻塞Task.WhenAll(taskList.ToArray()).ContinueWith((t) => this.DoSomething(“我是回调”)) ;
并发问题
对于共享变量,肯定会存在并发问题,这是由于同一时刻可能有多个线程获取了这个变量的值,当一个线程改变变量的值之后,另外一个线程持有的变量值还是原来的值,此时另外一个变量改变后将会覆盖之前线程改变的变量的值。从而造成并发问题
- 解决办法
- lock锁
- 安全队列
- …
//使用状态唯一的锁private static readonly object LockShare = new object();private void button_bingfa_Click(object sender, EventArgs e){List<int> initList = new List<int>();int shareSemaPhone = 0;List<Task> taskList = new List<Task>();for(int i = 0; i < 1000; i++){//开辟1000线程任务taskList.Add(Task.Run(() =>{lock (LockShare)//锁{int newI = i;initList.Add(newI);shareSemaPhone += 1;}}));}//等待线程执行完毕Task.WaitAll(taskList.ToArray());Console.WriteLine($"shareSemaPhone=>{shareSemaPhone}");Console.WriteLine($"initList count=>{initList.Count}");}