日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

学习笔记 --- 编码过程中常见的三种异步方式

發(fā)布時(shí)間:2025/7/14 59 豆豆
生活随笔 收集整理的這篇文章主要介紹了 学习笔记 --- 编码过程中常见的三种异步方式 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

實(shí)際的編碼過程中, 凡是涉及到網(wǎng)絡(luò)通信的代碼, 異步都是決不可缺少的. 那么什么是異步呢?

異步就是子線程, 異步通過開辟子線程來實(shí)現(xiàn), 所以一提到異步就應(yīng)該想到子線程. 即使不涉及網(wǎng)絡(luò)通信, 異步也是一種常用的編碼方式, 如: 在Winfor程序中, 某個(gè)耗時(shí)較長方法我們需要執(zhí)行10000次, 如果由主線程去循環(huán)10000次, 那么客戶的CPU占用率將居高不下, 客戶機(jī)器將慢如蝸牛, 甚至整個(gè)程序都會(huì)出現(xiàn)假死或崩潰的狀態(tài). 作為一名有追求的程序員, 這種情況是絕對(duì)不允許的. 其實(shí)不光是在Winform程序, 即使是在基于B/S的Web程序中, 異步通信也是很常見的, 比如: Ajax技術(shù). 在這里, 不討論具體的項(xiàng)目環(huán)境, 單說3種常見的異步編程(Asynchronous Programming)方式 和 簡要的提下B/S中的異步技術(shù) --- Ajax(參見博客中的<<3種Ajax的實(shí)現(xiàn)>>)

?

關(guān)于示例的說明: 我們舉個(gè)很簡單的例子: 計(jì)算1+2+3+...+99+100, 采用最笨的循環(huán)方法且每次循環(huán)Sleep 100毫秒. 由于窗體程序容易看出效果, 這里在主窗體(MainForm)中放置3個(gè)按鈕, 代表3中不同的異步方式. 當(dāng)點(diǎn)擊按鈕時(shí)通過this.Invoke()方法創(chuàng)建子窗體(SubForm), 在第一種異步方式中, 我們是在子線程中創(chuàng)建子窗體的, 如果只是簡單的使用new創(chuàng)建子窗體, 則子窗體會(huì)隨著子線程的結(jié)束而消亡, 結(jié)果就看不到了. 使用this.Invoke()方法可以在子線程中, 由主線程來創(chuàng)建子窗體, 這樣子線程執(zhí)行完后并不會(huì)銷毀主線程創(chuàng)建的窗體. 同時(shí)為了將結(jié)果顯示在子窗體的textbox中, 需要在子窗體的設(shè)計(jì)代碼中, 將textbox的修飾符設(shè)置為public的. 注意: 第二種異步方式中, 使用new創(chuàng)建了子窗體, 由于是在主線程執(zhí)行的new, 所以子窗體不會(huì)銷毀, 注意體會(huì)this.Invoke()的用法.

?

第一種異步: 使用System.Threading.Thread類 + Start()方法.
這種方法需要先New一個(gè)Thread類的對(duì)象, 在Thread類的構(gòu)造函數(shù)的參數(shù)列表中需要再new 一個(gè)TheadStart委托類的委托對(duì)象(還記得嗎? 委托是用來傳遞方法的), 該委托對(duì)象上綁定要執(zhí)行的處理方法. 最后, 只要在主線程中使用Thread類的對(duì)象調(diào)用Start()方法即可.

?

第二種異步: 使用委托 + AsyncCallback回調(diào)函數(shù).
這種方式首先要定義一個(gè)委托類型, 之后要在主線程中創(chuàng)建委托對(duì)象, 該委托對(duì)象綁定你要執(zhí)行的方法. 在委托對(duì)象上使用BeginInvoke方法開始異步, BeginInvoke方法的參數(shù)列表依次是委托對(duì)象綁定的方法的參數(shù)、new一個(gè)AsyncCallback的委托對(duì)象, 該對(duì)象綁定處理結(jié)果的方法(因?yàn)橐婚_始就創(chuàng)建了委托對(duì)象, 為避免混淆我個(gè)人喜歡將這個(gè)用于回調(diào)的委托稱為回調(diào)函數(shù))、委托對(duì)象的引用(一開始創(chuàng)建的委托對(duì)象).
其實(shí)BeginInvoke方法的最后一個(gè)參數(shù)就是我們一開始創(chuàng)建的委托對(duì)象的引用, 保存該引用的目的是為了能夠在子線程中調(diào)用一開始創(chuàng)建的委托對(duì)象上的EndInvoke方法以便處理結(jié)果. 處理結(jié)果的子線程方法(或者稱為結(jié)果處理方法, 也就是用于回調(diào)的委托上綁定的方法)的參數(shù)是IAsyncResult, 這個(gè)接口類型的參數(shù)實(shí)際上就是BeginInvoke方法中的最后一個(gè)參數(shù), 我們?cè)谶@個(gè)結(jié)果處理方法中, 可以通過EndInvoke方法獲得結(jié)果并顯示.

?

第三種方式: 使用Async結(jié)尾的方法 + 事件處理器.
以上的兩種異步是通用的異步手段, 你可以隨時(shí)使用他們實(shí)現(xiàn)異步操作. 但第3種借助事件處理器來完成異步操作的方式并不是隨時(shí)都可以使用的, 只有類庫提供了Async結(jié)尾的方法時(shí), 才可以使用. 我們通過Async結(jié)尾的方法來開辟子線程, 當(dāng)子線程結(jié)束時(shí)激發(fā)一個(gè)事件, 我們?cè)谶@個(gè)事件中完成結(jié)果處理代碼. 當(dāng)然, 我們也可以在類中自己實(shí)現(xiàn)Async結(jié)尾的方法, 記得常委同志還跟我討論過這個(gè)問題, 今天就額外寫個(gè)實(shí)現(xiàn).

?

第四種方式: Javascript中的異步技術(shù), 也就是傳說中Ajax技術(shù).
具體實(shí)例和代碼可以參考博客中的另外一篇文章<<3中Ajax的實(shí)現(xiàn)>>, 這里簡單陳述一下. 第一種Ajax技術(shù)就是在Javascript中異步獲取結(jié)果的方式, 它的實(shí)現(xiàn)原理其實(shí)就是onreadystatechange事件, 通過該事件上綁定的事件處理器來完成異步. 第二種Ajax技術(shù)要稍微復(fù)雜一下, 它的原理是借助AjaxPro.dll類庫, 在本地生成一個(gè)Javascript中用的代理類, 你可以用這個(gè)代理類來完成存取數(shù)據(jù)的操作. 第3種Ajax技術(shù), 就是微軟在VS2008中提供的Ajax控件, 利用該控件也可以很方便實(shí)現(xiàn)Ajax技術(shù), 使用也比較簡單跟著說明做即可.

?

//示例代碼:

//mainform.cs

代碼 using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace AsynchronousProgramming
{
public partial class Mainform : Form
{
public Mainform()
{
InitializeComponent();
Control.CheckForIllegalCrossThreadCalls
= false;
}

//#####通過Invoke方法使主線程獲得子線程的控制權(quán)#######
private delegate SubForm DelNewForm();
private SubForm createSubForm()
{
SubForm sf
= new SubForm();
sf.Show();
return sf;
}

//####################################################
private void button1_Click(object sender, EventArgs e)
{
#region 同步調(diào)用
//SubForm sf = new SubForm();
//sf.Show();
//sf.txt_show.Text = sf.Add(1,100).ToString(); //這里為簡單, 將參數(shù)硬編碼在這
#endregion

#region Thread類 + Start()方法 實(shí)現(xiàn)異步
System.Threading.Thread th
= new System.Threading.Thread(new System.Threading.ThreadStart(dealProcess));
th.Start();
#endregion
}

private void dealProcess()
{
//SubForm sf = new SubForm(); //直接在子線程中new子窗體, 線程結(jié)束子窗體就會(huì)關(guān)閉, 無法看到結(jié)果
SubForm sf = this.Invoke(new DelNewForm(createSubForm)) as SubForm; //第一種異步按鈕彈出的子窗體
sf.Show();
sf.txt_show.Text
= sf.Add(1,100).ToString();
}

//####################################################
SubForm subf; //第二種異步彈出的子窗體
delegate int DelAdd(int start, int end);
private void button2_Click(object sender, EventArgs e)
{
#region 委托 + AsyncCallback回調(diào)函數(shù) 實(shí)現(xiàn)異步
//subf = this.Invoke(new DelNewForm(createSubForm)) as SubForm;
subf = new SubForm(); //這里可以直接new SubForm(), 因?yàn)榈诙N異步子窗體不是在子線程中創(chuàng)建的, 不會(huì)隨著線程結(jié)束消亡
subf.Show();
DelAdd da
= new DelAdd(subf.Add);
da.BeginInvoke(
1,100,new AsyncCallback(dealAdd), da); //硬編碼參數(shù)
#endregion
}
private void dealAdd(IAsyncResult ia)
{
DelAdd da
= ia.AsyncState as DelAdd;
subf.txt_show.Text
= da.EndInvoke(ia).ToString();
}


//####################################################
SubForm subfm; //第三種異步彈出的子窗體
private void button3_Click(object sender, EventArgs e)
{
#region 使用Async結(jié)尾的方法 + 事件處理器 實(shí)現(xiàn)異步
//subfm = this.Invoke(new DelNewForm(createSubForm)) as SubForm;
subfm = new SubForm();
subfm.Show();
subfm.AccumulateAsync(
1, 100); //我們?cè)赟ubForm.cs中自定義的Async異步方法(硬編碼參數(shù))
subfm.AccumulateCompleted += new AccumulateCompletedHandler(subfm_AccumulateCompleted); //異步計(jì)算完成后觸發(fā)的AccumulatedCompleted事件
#endregion
}

void subfm_AccumulateCompleted(object sender, AccumulatedCompletedEventArgs e)
{
subfm.txt_show.Text
= e.Result.ToString();
}
}
}

?

//SubForm.cs

代碼 using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace AsynchronousProgramming
{
public partial class SubForm : Form
{
public SubForm()
{
InitializeComponent();
//this.AccumulateCompleted += new AccumulateCompletedHandler(SubForm_AccumulateCompleted); //第三種異步 --- 注冊(cè)事件
}

//########################################################
#region 第一種異步(Thread類 + Start()方法) 和 第二種異步(委托 + AsyncCallback回調(diào)函數(shù)) 調(diào)用的方法
public int Add(int start , int end)
{
int sum = 0;
for (int i = start; i <= end; i++)
{
System.Threading.Thread.Sleep(
100);
sum
+= i;
}
return sum;
}
#endregion

//########################################################
#region 第三種異步(Async結(jié)尾的方法 + 事件處理器) 調(diào)用的方法

//實(shí)際計(jì)算的方法
public object Accumulate(int start, int end)
{
int result = 0;
for (int i = start; i <= end; i++)
{
System.Threading.Thread.Sleep(
100);
result
+= i;
}
return (object)result;
}

//3. 定義事件, 該事件就是mainform.cs中用來獲取結(jié)果的事件
public event AccumulateCompletedHandler AccumulateCompleted;

//4. 注冊(cè)事件, 事件的注冊(cè)工作通常放在構(gòu)造函數(shù)中, 也可以由事件來注冊(cè). 這里實(shí)際的事件注冊(cè)過程在mainform.cs中注冊(cè), 事件處理器也放在mainform.cs中

//5. 觸發(fā)事件由OnAccumulateCompleted執(zhí)行
public void OnAccumulateCompleted(object obj)
{
if (AccumulateCompleted != null)
{
this.AccumulateCompleted(this, new AccumulatedCompletedEventArgs(new object[] { obj }));
}
}

private delegate object AccumulateOperation(int start, int end);
//對(duì)外提供的AddAsync方法
public void AccumulateAsync(int start, int end) //注意: Async結(jié)尾的方法將開辟子線程, 所以返回值為void
{
//此時(shí), 應(yīng)該異步的調(diào)用Accumulate方法, 這里用委托+回調(diào)方法來模擬
AccumulateOperation ao = new AccumulateOperation(Accumulate);
ao.BeginInvoke(start, end,
new AsyncCallback(dealAccumulate), ao);
}

private void dealAccumulate(IAsyncResult ia)
{
//在子線程中調(diào)用Add方法
AccumulateOperation ao = ia.AsyncState as AccumulateOperation;
object result = ao.EndInvoke(ia);
if (result != null)
{
this.OnAccumulateCompleted(result); //結(jié)果計(jì)算出來后, 觸發(fā)事件, 事件處理方法在mainform.cs中
}
}
#endregion
}

//1. 定義累加結(jié)果處理方法(事件處理器)的參數(shù)對(duì)象, 因?yàn)槲覀儚脑撌录幚砥髦蝎@得結(jié)果信息, 因此參數(shù)對(duì)象只包含處理結(jié)果的信息即可
public class AccumulatedCompletedEventArgs : EventArgs //為了擴(kuò)大結(jié)果的表示范圍, 采用object[]做結(jié)果信息類型
{
private object[] _result;

public AccumulatedCompletedEventArgs(object[] result)
{
this._result = result;
}
public int Result
{
get { return (int)this._result[0];}
}
}

//2. 定義委托類型, 該委托類型用來封裝mainform.cs中處理結(jié)果的方法(即: AccumulatedCompleted事件的處理器)
public delegate void AccumulateCompletedHandler(object sender, AccumulatedCompletedEventArgs e);
}

?

?

轉(zhuǎn)載于:https://www.cnblogs.com/cs_net/archive/2011/01/05/1926174.html

總結(jié)

以上是生活随笔為你收集整理的学习笔记 --- 编码过程中常见的三种异步方式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。