目录
同步与异步的区别
异步是基于多线程的,一个操作再执行时不会阻止其他线程的工作。
1、同步方法的所有计算都在主线程进行,可能会卡UI界面;异步方法的所有计算都在子线程中,不会卡界面
2、异步是多线程的,对于CPU的利用率高,资源耗费多;同步方法对于CPU利用率低
异步的实现方式
1、delegate委托的异步调用
步骤:
1、定义同步方法
public void Func();
2、定义类型与同步方法一致的委托
public delegate void FuncDelegate();
3、定义委托变量,与同步方法进行绑定
FuncDelegate delegate=new FuncDelegate(Func);
4、调用委托的BeginInvoke()和EndInvoke(),从而实现异步调用同步方法的效果
delegate.BeginInvoke(null,null); //无回调函数则为null
对于无参无返回值和有参无返回值两种情况,直接调用委托的BeginInvoke方法。
a)BeginInvoke
public IAsyncResult BeginInvoke(int p1,out double p2,ref bool p3,AsyncCallBack callback,object AsyncState)
IAsyncResult:返回的接口、监控
p1/p2/p3:同步方法的参数
callback:回调函数
AsyncState:传给回调函数的参数
b)CallBack:BeginInvoke执行结束会自动执行回调函数
public static void CallBackMethod(IAsyncResult ia){}
ia.AsyncState :表示传递给回调函数的参数
ia.AsyncWaitHandle.WaitOne(int mms): 线程等待mms毫秒以便异步方法执行完成
ia.AsyncDelegate: 获得委托的返回值
public static void CallBackMethod(IAsyncResult ia)
{
AsyncResult asyncresult=(AsyncResult)ia;
//获取回调函数的参数
string parameter=asyncresult.AsyncState.ToString();
//获取异步调用的委托
FuncDelegate delegate=(FuncDelegate)asyncresult.AsyncDelegate;
int re=delegate.EndInvoke(ia);
}
c)EndInvoke:在线程池种清理完成的异步方法
public 返回值 EndInvoke(out double p2,ref bool p3,IAsyncResult ia)
返回值:异步方法的返回值
p2/p3:只传入out参数
ia:BeginInvoke的返回值
说明:
如果调用异步方法的主线程需要获取异步的结果或等待异步方法的完成,那么可以在主调函数种调用EndInvoke(会阻塞主线程,卡界面)
如果不需要异步方法的结果,不需要等异步方法执行结束,可以在回调函数中调用EndInvoke(不会阻塞主线程,不会卡界面)
例子
//主线程
public void MainFunc()
{
//无参无返回值
delegate.BeginInvoke(null,null);
//有参无返回值
delegate.BeginInvoke(18,"Tom",null,null);
//无参有返回值
IAsyncResult ia=delegate.BeginInvoke(null,null);
ia.AsyncWaitHandle.WaitOne(1000); //等待一定时间以便异步执行完毕
int re=delegate.EndInvoke(ia); //得到异步程序的返回值, 获取子线程的返回值会阻塞主线程(在回调函数中调用不会阻塞主线程)
//有参有返回值
IAsyncResult ia=delegate.BeginInvoke(18,"Tom",null,null);
int re=delegate.EndInvoke(ia);
//有回调函数,有回调函数的参数
IAsyncResult ia=delegate.BeginInvoke(CallBackMethod,asyncState);
}
2、Thread
默认不支持返回值,不支持回调函数
public void MainFunc()
{
//无参无返回值
ThreadStart threadstart=new ThreadStart(Func); //Func同步方法
Thread thread=new Thread(threadstart);
thread.Start();
//有参无返回值
ParameterizedThreadStart threadstart=new ParameterizedThreadStart(Func); //Func有参无返回值,参数必须是object类型
Thread thread=new Thread(threadstart);
thread.Start(18);
//无参有返回值
Func<int> func=new Func<int>(Func); //1、定义一个有返回值的委托,绑定同步方法
Func<int> begininvoke=BeginInvoke<int>(func); //2、定义一个参数是委托,返回委托的BeginInvoke泛函,内部用Thread实现
int re=begininvoke.Invoke(); //3、Invoke同步实现 ,会阻塞主线程
//有参有返回值
Func<int,string,int> func=new Func<int,string,int>(func); //1、func是有两个参数,一个int返回值的同步方法
Func<int> begininvoke=BeginInvoke<int>(func); //2、BeginInvoke是参数和返回值均为委托的泛函,内部用Thread实现
int re=begininvoke.Invoke(); //3、同步实现
}
public Func<T> BeginInvoke<T>(Func<T> func)
{
T t=default(T);
ThreadStart thread=new ThreadStart(()=>
{
func.Invoke();
})
Thread thread=new Thread(threadstart);
thread.Start();
return new Func<T>(()=>
{
thread.Join();
return t;
})
}
注意:
方法中的委托和同步方法不一定相同,根据具体情况改变参数和返回值。
如果需要回调函数,则在BeginInvoke方法中加入回调函数的调用
Func.Invoke();
CallBackMethod.Invoke();
3、Task
public void MainFunc()
{
//Task类创建task Start
Task task=new Task(Func);
task.Start();
//TaskFactory类创建task并自动启动 StartNew
TaskFactory taskfactory=new TaskFactory();
Task task=taskfactory.StartNew(Func);
//Task类创建task并自动启动 Run
Task task=Task.Run(Func);
//ContinueWith 不会阻塞主线程
Task task1=new Task(Func);
task1.ContinueWith((a)=> //创建一个task1执行完之后继续执行的任务
{
...
})
//ContinueWhenAny 不会阻塞主线程
TaskFactory taskfactory=new TaskFactory();
Task task1=taskfactory.StartNew(()=>{...});
Task task2=taskfactory.StartNew(()=>{...});
Task task3=taskfactory.StartNew(()=>{...});
taskfactory.ContinueWhenAny(new Task[]{task1,task2,task3},(a)=>{...}); //创建一个任务,在任务组中任意一个任务完成之后开始执行
//ContinueWhenAll 不会阻塞主线程
taskfactory.ContinueWhenAll(new Task[]{task1,task2,task3},(a)=>{...}); //创建一个任务,在任务组中所有任务完成之后开始执行
//WaitAny 会阻塞主线程
Task.WaitAny(new Task[]{task1,task2,task3}); //等待任务组中任意一个任务完成开始往下执行
//将任务组和WaitAny放到Task中可以解决阻塞主线程的问题
//WaitAll 会阻塞主线程
Task.WaitAll(new Task[]{task1,task2,task3}); //等待任务组中所有任务完成之后开始往下执行
//将任务组和WaitAll放到Task中可以解决阻塞主线程的问题
//WhenAny 不会阻塞主线程
Task task=Task.WhenAny(new Task[]{task1,task2,task3});
task.ContinueWith((a)=>{...});
//WhenAll 不会阻塞主线程
Task task=Task.WhenAll(new Task[]{task1,task2,task3});
task.ContinueWith(()=>{...});
//有参数有返回值 会阻塞主线程
Task<int> task=new Task<int>(new Func<object,int>((a)=>{...}),"aaa");
task.Start();
int re=task.Result;
//需要获取结果时将其放到task中异步执行可以解决阻塞主线程的问题
}
4、ThreadPool
public void MainFunc()
{
//QueueUserWorkItem 不会阻塞主线程 多个工作项是异步执行的
ThreadPool.QueueUserWorkItem(new WaitCallBack((a)=>{...}));
ThreadPool.QueueUserWorkItem(new WaitCallBack((b)=>{}),"bbb"); //可以传递一个object类型的参数
}
5、Parallel
public void MainFunc()
{
//For 会阻塞主线程 3个线程异步执行,执行完之后才会开启新的3个线程
ParallelOptions options=new ParallelOptions();
options.MaxDegreeOfParallelism=3;
Parallel.For(1,6,options,(a,loopState)=>{
...
});
//Foreach 会阻塞主线程 3个线程异步执行,执行完3个之后才会开启新的3个线程
Parallel.Foreach(int[]{1,2,3,4,5},options,(a,loopState)=>{
...
})
//Invoke 会阻塞主线程 3个线程异步执行,执行完1个开始执行新的任务,保证3个同时进行
Parallel.Invoke(options,
()=>{...},
()=>{...},
()=>{...},
()=>{...}
);
}
6、async&await
public void MainFunc()
{
AsyncFunc(); //异步方法,内部有await
}
public Async void AsyncFunc()
{
Task task1=new Task(()=>{...});
await task1;
//遇到await之后开启新线程,主线程继续执行主函数后面的程序
//AsyncFunc往后的内容只能等task1执行完之后才能继续,且由主线程接手
Task task2=new Task(()=>{...});
await task2;
}
```