三,异步回调.顺序控制!,这次算是对委托使用的异步补充吧
【异步回调】
private void button3_Click(object sender, EventArgs e)
{
Console.WriteLine();
Console.WriteLine("****************** 异步方法 start {0}********************", Thread.CurrentThread.ManagedThreadId);
Action<string> action = new Action<string>(this.DoSomethingLong);
#region 【回调】
1 发起异步调用时,传递一个AsyncCallback委托实例,该实例会在异步调用完成后,由这个子线程去调用委托,就能保证顺序
调用回调的委托,参数何来?其实是委托异步调用的结果作为参数去调用的
AsyncState状态参数一般是用来提供给回调使用的,就是 BeginInvoke 方法中 第三个参数的值
//asyncResult是异步调用的结果 但不是委托自身调用后的结果
IAsyncResult asyncResult = null;
AsyncCallback callback = new AsyncCallback((ar) =>
{
Console.WriteLine(object.ReferenceEquals(ar, asyncResult));
Console.WriteLine(ar.AsyncState);
if (ar.IsCompleted)
{
Console.WriteLine($"计算任务已完成 {Thread.CurrentThread.ManagedThreadId}");
}
//回调时候更新操作的UI
this.BeginInvoke(new Action(() =>
{
this.label1.Text = $"当前计算已完成{Thread.CurrentThread.ManagedThreadId}";
}));//会找主线程完成, CS还勉强可以这样做,但是BS是做不到的
});
for (int i = 0; i < 4; i++)
{
asyncResult = action.BeginInvoke("btnAsyncAdvanced_Click", callback, "aaa" + i); //callback 回调,
}
#endregion
Console.ReadKey();
}
【异步等待】
private void button4_Click(object sender, EventArgs e)
{
Console.WriteLine();
Console.WriteLine("****************** 异步方法 start {0}********************", Thread.CurrentThread.ManagedThreadId);
Action<string> action = new Action<string>(this.DoSomethingLong);
#region 等待
执行完计算后,提示用户说计算完成---如果用回调的方式,是没办法在请求结束后再去通知用户的,不能用子线程去完成通知的(尤其是BS,请求结束了就没办法再次通知)
IAsyncResult asyncResult = action.BeginInvoke("btnAsyncAdvanced_Click", null, null);
完成了顺序控制! 但是其实是主线程在等待计算,会阻塞(卡界面)
为啥不就一个主线程? 是为了进度条,为了边计算边提示用户
可能有延迟,最多延迟200ms
int i = 0;
while (!asyncResult.IsCompleted) //回调完成,线程执行完毕
{
if (i < 10)
{
Console.WriteLine($"当前计算已经完成{i++ * 10}%");
}
else
{
Console.WriteLine($"当前计算已经完成99.99%");
}
Thread.Sleep(300);
}
Console.WriteLine("当前计算已完成");
this.label1.Text = "当前计算已完成";
#endregion
}
【信号量】
private void button5_Click(object sender, EventArgs e)
{
Console.WriteLine();
Console.WriteLine("****************** 异步方法 start {0}********************", Thread.CurrentThread.ManagedThreadId);
Action<string> action = new Action<string>(this.DoSomethingLong);
#region 信号量
// 零延迟同步 asyncResult.AsyncWaitHandle.WaitOne(); //有很多重载,注意看
//等待时不能做别的了。。其实是为了能并发,保证并发后都完成才继续
IAsyncResult asyncResult = action.BeginInvoke("btnAsyncAdvanced_Click", null, null);
//asyncResult.AsyncWaitHandle.WaitOne();//如果在做其他事情之前,先开始了等待,那么会阻塞,等待action执行方法完成
Console.WriteLine("其他事情1");
Console.WriteLine("其他事情2");
Console.WriteLine("其他事情3");
Console.WriteLine("其他事情4");
Console.WriteLine("其他事情5");
asyncResult.AsyncWaitHandle.WaitOne(-1);//一直等待
Console.WriteLine($"计算等待前{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}");
//asyncResult.AsyncWaitHandle.WaitOne(1000);//最多等待1000ms 超时就不等了 像调用接口时会用上
//Console.WriteLine($"当前计算已完成{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}");
//this.lblInfo.Text = "当前计算已完成";
#endregion
}
【EndInvoke】
private void button6_Click(object sender, EventArgs e)
{
Console.WriteLine();
Console.WriteLine("****************** 异步方法 start {0}********************", Thread.CurrentThread.ManagedThreadId);
Action<string> action = new Action<string>(this.DoSomethingLong);
#region EndInvoke
零延迟的等待 是为了获取委托自身调用的返回值
//对于每个异步操作,只能调用一次 EndInvoke
IAsyncResult asyncResult = action.BeginInvoke("btnAsyncAdvanced_Click", null, null);
//Console.WriteLine($"计算等待前{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}");
//action.EndInvoke(asyncResult);
//asyncResult.AsyncWaitHandle.WaitOne(100);//最多等待1000ms 超时就不等了 像调用接口时会用上
//Console.WriteLine($"当前计算已完成{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}");
//asyncResult是异步调用的结果 但不是委托自身调用后的结果
Func<int> func = new Func<int>(() =>
{
Thread.Sleep(2000);
return DateTime.Now.Year;
});
int iResult = func.Invoke();//委托自身调用后的结果
Console.WriteLine($"委托自身的返回:{ iResult }");
IAsyncResult iAsyncResult = func.BeginInvoke((ar) =>
{
int iResultAsyncIn = func.EndInvoke(ar); //回调结束后接受返回值
Console.WriteLine($"通过委托自身的异步调用获取返回值:{iResultAsyncIn}");
}, null);//异步调用的结果
//EndInvoke//只能够调用一次,一对一,不然出现异常
#endregion
}
暂时写到这,欢迎指教!