任何的异步多线程,都是跟委托相关,没有委托,啥也没有
多线程1.0 1.1 Thread
Thread:是.Net框架封装的一个类,描述线程这个东西
同步方法:发起一个调用,一定要等着计算结束才运行下一行
异步方法:发起一个调用,不会等着计算结束,而是直接开始运行下一行
异步多线程:多线程说的 是CLR线程 异步IO线程
- 同步方法卡界面,以为ui线程忙于计算,异步多线程方法不卡界面,主线程闲置,计算任务交给子线程在做;
- 同步方法慢,只有一个线程计算,异步多线程方法快,多个线程并发计算;多线程的资源消耗更多,线程并不是越多越好(资源有限/管理线程也消耗资源)
- 异步多线程是无序的,启动无序 执行时间不确定 结束无序,所有我们不要试图通过顺序或者时间等待来控制流程
怎么控制顺序?
回调 等待 状态
AsyncCallback 回调
IsCompleted 状态
iAsyncResult.AsyncWaitHandle.WaitOne()//一直等待任务完成,第一时间进入下一行
iAsyncResult.AsyncWaitHandle.WaitOne(-1)//一直等待任务完成,第一时间进入下一行
iAsyncResult.AsyncWaitHandle.WaitOne(1000)//最多等待1000毫秒,否在进入下一行
Act.EndInvoke(iAsyncResult);//等待
String resultIn=func.EndInvoke(ar);//对于每个异步调用,只能调用一次 EndInvoke
ThreadStart threadStart = new ThreadStart(() =>
{
Thread.Sleep(5000);
this.DoSomethingLong("btnThreads_Click");//这是一个自己定义的私有方法
});
Thread thread = new Thread(threadStart);
thread.IsBackground = true;//变成后台线程
thread.Start();//默认是前台线程,UI线程退出后,还会继续执行完;后台线程就直接退出了
//thread.Suspend();//暂停
//thread.Resume();//恢复
//thread.Join();//做等待
//thread.Abort();//销毁
//while (thread.ThreadState != System.Threading.ThreadState.Running)
//{//线程是否还在运行,以可以起到等待的效果
//}
ThreadPool 线程池 2.0 封装
- 去掉各种 api 避免滥用,降低复杂度
- 池化:1减少创建/销毁的成本 2 限制最大线程数量
ThreadPool.QueueUserWorkItem(o=>
{
Thread.Sleep(5000);
//代码段
});
没有需求,就别等待,阻塞线程
ManualResetEvent 状态标
ManualResetEvent mre = new ManualResetEvent(false);
mre.WaitOne();//状态标为false时,不会过这个方法
mre.Set();//打开
mre.Reset();//关闭
ManualResetEvent mre = new ManualResetEvent(false);//false 关闭
new Action(() =>
{
Thread.Sleep(5000);
Console.WriteLine("委托的异步调用");
mre.Set();//打开
}).BeginInvoke(null, null);
mre.WaitOne();
Console.WriteLine("12345");
mre.Reset();//关闭
new Action(() =>
{
Thread.Sleep(5000);
Console.WriteLine("委托的异步调用2");
mre.Set();//打开
}).BeginInvoke(null, null);
mre.WaitOne();
Console.WriteLine("23456");
Task 3.0
使用的是线程池的线程 全部是后台线程
API很强大
多线程:业务是可以并发执行
千万不要在Task里面去启动Task
启动:
Task.Run();
TaskFactory taskFactory=Task.Factory;//new TaskFactory();
taskFactory.StartNew();//启动
Task.WaitAny(taskList.toArray());//执行玩一个线程后开始执行
Task.WaitAll();//全部执行玩
//回调
taskFactory.ContinueWhenAll();
taskFactory.ContinueWhenAny();
4.0 Parallel
跟task很像 ==task+waitall 启动多个线程计算 主线程也参与计算,节约了一个线程
Parallel.Invoke();//
Parallel.For(0,5,t=>
{
//代码块
})
Parallel.ForEach(new int[]{1,2,3,4,5}, options, (t,state)=>
{
//代码块
this.DoSomethingLog($”btnParallel_click_00{t}”);
//state.Stop();//
//state.Break();//
});
ParalleOptions options=new ParalleOptions()//同时在线 线程
{
MaxDegreeOfParalleLism=3
};
ThreadCore 异常处理
多线程里的异常是会被丢掉,除非waitall
建议 多线程里面,是不允许异常,以就是内部try catch,自己处理
线程取消
线程取消不是操作线程,而是操作共享信号量(共享变量,多个线程都能访问到的东西,变量/数据库的数据/硬盘数据)
每个线程在执行的过程中,进程去超快下这个信号量,然后自己结束自己
线程不能别人终止,只能自己干掉自己,延迟是少不了的
CancellationTakensource cts = new CancellationTakensource(); //bool值
cts.IsCancllationRequested //检查信号
cts.Cancel();//
多线程临时变量
For(int i=0;i<5;i++){
Int k-i;
New Action(()=>
{
Thread.Sleep(100);
Console.Writeline(k);
Console.Writeline(i);
}).BeginInvoke(null,null);
}
i 只有一个,真实 实际的时候,已经是5了
k 有多个,每次都是独立的k,跟i没有关系
线程安全
公有变量:都能访问局部变量/全局变量/数据库的一个值/硬盘文件
线程内部不共享的是安全的
多个线程同时操作一个变量,变量的值可能被覆盖
解决多线程冲突第一个办法:lock的方法块里面是单线程 去掉多线程,lock里面的代码要尽量的少
Lock(){//lock后的方法块,任意时刻只有一个线程可以进入
}
解决多线程冲突第二个办法:没有冲突,从数据上隔离开
Lock==Monitor.Enter 检查下这个变量,有没有被lock 有就等着,没有就占有者,然后进去执行,执行玩释放
lock(this)锁定当前实例,别的地方如果要使用这个变量呢?都被锁定了
如果每个实例想要单独的锁定,private object
String a=”123456’ lock(a) string b=”123456” 享元模式的内存分配,字符串值是唯一的,会锁定的变量b
Private static readonly object btnThreadCore_Click_Lock=new object();
await/async C#5.0 .Net Framework4.5
await/async 是语法糖,本身是编译器提供的功能
async 用来修饰方法的
await 只能出现在Task 前面
await/async 本身不是线程
不推荐void返回值,使用Task来代替
Task和Task能够使用await,Task.WhenAny,Task.Whenall等方式组合使用,Async Void不行
无返回值
主线程越到await返回,执行主线程任务
子线程执行 其实是封装成委托,在task之后成为回调(编译器功能 状态机实现)
这个回调的线程是不确定的:可能是主线程,可能是子线程 以可能是其他的线程
t.Wait();//主线程等待Task完成 或者t.Result;