欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

.NET1.0版本中的異步編程模型(APM)

 更新時(shí)間:2022年06月09日 09:19:30   作者:springsnow  
這篇文章介紹了.NET1.0版本中的異步編程模型(APM),文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

一、概念

.NET 1.0提出了APM(Asynchronous Programming Model)即異步編程模式。

.NET的類庫有以BeginXXX和EndXXX類似的方法,就是使用異步編程模型。

NET Framework很多類也實(shí)現(xiàn)了該模式,同時(shí)我們也可以自定義類來實(shí)現(xiàn)該模式,即在自定義的類中實(shí)現(xiàn)返回類型為IAsyncResult接口的BeginXXX方法和EndXXX方法,另外委托類型也定義了BeginInvoke和EndInvoke方法。

異步編程模型的本質(zhì)

利用委托和線程池幫助我們實(shí)現(xiàn)異步編程模型模式。

該模式利用一個線程池線程去執(zhí)行一個操作,在FileStream類BeginRead方法中就是執(zhí)行一個讀取文件操作,該線程池線程會立即將控制權(quán)返回給調(diào)用線程,此時(shí)線程池線程在后臺進(jìn)行這個異步操作;

異步操作完成之后,通過回調(diào)函數(shù)來獲取異步操作返回的結(jié)果,此時(shí)就是利用委托的機(jī)制。

1、BeginXxx方法——開始執(zhí)行異步操作介紹

當(dāng)需要讀取文件中的內(nèi)容時(shí),我們通常會采用FileStream的同步方法Read來讀取,該同步方法的定義為:

// 從文件流中讀取字節(jié)塊并將該數(shù)據(jù)寫入給定的字節(jié)數(shù)組中
public override int Read(byte[] array, int offset, int count )

該同步方法會堵塞執(zhí)行的線程。

可以通過BeginRead方法來實(shí)現(xiàn)異步編程,使讀取操作不再堵塞UI線程。BeginRead方法代表異步執(zhí)行Read操作,并返回實(shí)現(xiàn)IAsyncResult接口的對象,該對象存儲著異步操作的信息。

// 開始異步讀操作
// 前面的3個參數(shù)和同步方法代表的意思一樣,這里就不說了,可以看到這里多出了2個參數(shù)
// userCallback代表當(dāng)異步IO操作完成時(shí),你希望由一個線程池線程執(zhí)行的方法,該方法必須匹配AsyncCallback委托
// stateObject代表你希望轉(zhuǎn)發(fā)給回調(diào)方法的一個對象的引用,在回調(diào)方法中,可以查詢IAsyncResult接口的AsyncState屬性來訪問該對象
public override IAsyncResult BeginRead(byte[] array, int offset, int numBytes, AsyncCallback userCallback, Object stateObject)

從上面的代碼中可以看出異步方法和同步方法的區(qū)別,如果你在使用該異步方法時(shí),不希望異步操作完成后調(diào)用任何代碼,你可以把userCallback參數(shù)設(shè)置為null

2、EndXxx方法——結(jié)束異步操作介紹

前面介紹完了BeginXxx方法,我們看到所有BeginXxx方法返回的都是實(shí)現(xiàn)了IAsyncResult接口的一個對象,并不是對應(yīng)的同步方法那樣直接得到結(jié)果。

此時(shí)我們需要調(diào)用對應(yīng)的EndXxx方法來結(jié)束異步操作,并向該方法傳遞IAsyncResult對象,EndXxx方法的返回類型就是和同步方法一樣的。例如,FileStreamEndRead方法返回一個Int32來代表從文件流中實(shí)際讀取的字節(jié)數(shù)。

// 摘要:  等待掛起的異步讀取完成。
// asyncResult:對要完成的掛起異步請求的引用。
// 返回結(jié)果: 從流中讀取的字節(jié)數(shù).
public virtual int EndRead(IAsyncResult asyncResult);

對于訪問異步操作的結(jié)果,APM的首選方式是:
使用 AsyncCallback委托來指定操作完成時(shí)要調(diào)用的方法,在操作完成后調(diào)用的方法中調(diào)用EndXxx操作來獲得異步操作的結(jié)果。

二、APM示例:

代碼:

private static void Main(string[] args)
{
    string downUrl = "http://download.microsoft.com/download/5/B/9/5B924336-AA5D-4903-95A0-56C6336E32C9/TAP.docx";
    DownLoadFileSync(downUrl);  //同步下載文件,在下載操作完成之后我們才可以看到"Start DownLoad File......." 消息顯示
    DownloadFileAsync(downUrl); //異步下載文件,在下載操作完成之前我們就可以看到"Start DownLoad File......." 消息顯示
    Console.WriteLine("開始下載文件.........");
    Console.ReadLine();
}

//同步下載文件
private static void DownLoadFileSync(string url)
{
    RequestState req = new RequestState(); // 創(chuàng)建一個 RequestState 實(shí)例
    try
    {
        HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create(url);   // 初始化一個  HttpWebRequest 對象
        req.request = myHttpWebRequest; // 指派 HttpWebRequest實(shí)例到requestState的request字段.
        req.response = (HttpWebResponse)myHttpWebRequest.GetResponse();
        req.streamResponse = req.response.GetResponseStream();

        int readSize = req.streamResponse.Read(req.BufferRead, 0, req.BufferRead.Length);
        while (readSize > 0)
        {
            req.filestream.Write(req.BufferRead, 0, readSize);
            readSize = req.streamResponse.Read(req.BufferRead, 0, req.BufferRead.Length);
        }

        Console.WriteLine("\n此文件的長度是: {0}", req.filestream.Length);
        Console.WriteLine("下載完成,下載路徑是: {0}", req.savepath);
    }
    catch (Exception e)
    {
        Console.WriteLine("錯誤信息:{0}", e.Message);
    }
    finally
    {
        req.response.Close();
        req.filestream.Close();
    }
}
 
//異步下載文件
private static void DownloadFileAsync(string url)
{
    try
    {
        HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create(url);
        RequestState req = new RequestState();
        req.request = myHttpWebRequest;
        myHttpWebRequest.BeginGetResponse(new AsyncCallback(ResponseCallback), req);
    }
    catch (Exception e)
    {
        Console.WriteLine("錯誤信息:{0}", e.Message);
    }
}

//每個異步操作完成時(shí),將調(diào)用下面的方法
private static void ResponseCallback(IAsyncResult callbackresult)
{
    RequestState req = (RequestState)callbackresult.AsyncState; // 獲取 RequestState 對象
    HttpWebRequest myHttpRequest = req.request;
    req.response = (HttpWebResponse)myHttpRequest.EndGetResponse(callbackresult); // 結(jié)束一個對英特網(wǎng)資源的的異步請求
    Stream responseStream = req.response.GetResponseStream(); //從服務(wù)器獲取響應(yīng)流
    req.streamResponse = responseStream;
    IAsyncResult asynchronousRead = responseStream.BeginRead(req.BufferRead, 0, req.BufferRead.Length, ReadCallBack, req);//異步讀取流到字節(jié)數(shù)組
}

// 寫字節(jié)數(shù)組到 FileStream
private static void ReadCallBack(IAsyncResult asyncResult)
{
    try
    {
        RequestState req = (RequestState)asyncResult.AsyncState; // 獲取 RequestState 對象
        Stream responserStream = req.streamResponse;   //從RequestState對象中獲取 Response Stream

        int readSize = responserStream.EndRead(asyncResult);
        if (readSize > 0)
        {
            req.filestream.Write(req.BufferRead, 0, readSize);
            responserStream.BeginRead(req.BufferRead, 0, req.BufferRead.Length, ReadCallBack, req);//循環(huán)調(diào)用ReadCallBack方法。
        }
        else
        {
            Console.WriteLine("\n此文件的長度是: {0}", req.filestream.Length);
            Console.WriteLine("下載完成,下載路徑是: {0}", req.savepath);
            req.response.Close();
            req.filestream.Close();
        }
    }
    catch (Exception e)
    {
        Console.WriteLine("錯誤信息:{0}", e.Message);
    }
}

//存儲請求的狀態(tài)類
public class RequestState
{
    public int BufferSize = 1024;
    public string savepath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\TAP.docx";
    public byte[] BufferRead;
    public HttpWebRequest request;
    public HttpWebResponse response;
    public Stream streamResponse;
    public FileStream filestream;

    public RequestState()
    {
        BufferRead = new byte[BufferSize];
        request = null;
        streamResponse = null;
        if (File.Exists(savepath))
        {
            File.Delete(savepath);
        }
        filestream = new FileStream(savepath, FileMode.OpenOrCreate);
    }
}

運(yùn)行結(jié)果:

使用同步方法下載文件的運(yùn)行結(jié)果為:(從運(yùn)行結(jié)果也可以看出,調(diào)用的是同步方法時(shí),此時(shí)會堵塞主線程,直到文件的下載操作被完成之后主線程才繼續(xù)執(zhí)行后面的代碼)

使用APM異步編程:運(yùn)行結(jié)果為(從運(yùn)行結(jié)果也可以看出,在主線程中調(diào)用 DownloadFileAsync(downUrl)方法時(shí),DownloadFileAsync(downUrl)方法中的req.BeginGetResponse調(diào)用被沒有阻塞調(diào)用線程(即主線程),而是立即返回到主線程,是主線程后面的代碼可以立即執(zhí)行)

三、委托實(shí)例的異步調(diào)用(BeginInvoke、EndInvoke方法

在前面的介紹中已經(jīng)提到委托類型也會定義了BeginInvoke方法和EndInvoke方法,所以委托類型也實(shí)現(xiàn)了異步編程模型,所以可以使用委托的BeginInvokeEndInvoke方法來回調(diào)同步方法從而實(shí)現(xiàn)異步編程。

因?yàn)檎{(diào)用委托的BeginInvoke方法來執(zhí)行一個同步方法時(shí),此時(shí)會使用線程池線程回調(diào)這個同步方法并立即返回到調(diào)用線程中,由于耗時(shí)操作在另外一個線程上運(yùn)行,所以執(zhí)行BeginInvoke方法的主線程就不會被堵塞。

下面實(shí)現(xiàn)在線程池線程中如何更新GUI線程中窗體。

// 定義用來實(shí)現(xiàn)異步編程的委托
private delegate string AsyncMethodCaller(string fileurl);

private void btnDownLoad_Click(object sender, EventArgs e)
{
    AsyncMethodCaller methodCaller = new AsyncMethodCaller(DownLoadFileSync);//DownLoadFileSync為同步下載文件的方法
    methodCaller.BeginInvoke(this.txbUrl.Text.Trim(), GetResult, null);
}

// 異步操作完成時(shí)執(zhí)行的方法
private void GetResult(IAsyncResult result)
{
    AsyncMethodCaller caller = (AsyncMethodCaller)((AsyncResult)result).AsyncDelegate;// 或者(AsyncMethodCaller)result.AsyncState;
    string returnstring = caller.EndInvoke(result); // 調(diào)用EndInvoke去等待異步調(diào)用完成并且獲得返回值,如果異步調(diào)用尚未完成,則 EndInvoke 會一直阻止調(diào)用線程,直到異步調(diào)用完成

    // 然后Invoke方法來使更新GUI操作方法由GUI 線程去執(zhí)行
    this.Invoke(new MethodInvoker(() =>
    {
        rtbState.Text = returnstring;
        btnDownLoad.Enabled = true;
    }));
}

運(yùn)行的結(jié)果為:

上例子中使用了控件的Invoke方式進(jìn)行異步回調(diào)訪問控件的方法,其背后是通過獲得GUI線程的同步上文對象SynchronizationContext,然后同步調(diào)用同步上下文對象的post方法把要調(diào)用的方法交給GUI線程去處理。

四、task實(shí)例

假如現(xiàn)在有這樣的一個需求,我們需要從3個txt文件中讀取字符,然后進(jìn)行倒序,前提是不能阻塞主線程。

如果不用task的話我可能會用工作線程去監(jiān)視一個bool變量來判斷文件是否全部讀取完畢,然后再進(jìn)行倒序,我也說了,相對task來說還是比較麻煩的,這里我就用task來實(shí)現(xiàn)。

private static void Main()
{
    string[] array = { "C://1.txt", "C://2.txt", "C://3.txt" };
    List<Task<string>> taskList = new List<Task<string>>(3);
    foreach (var item in array)
    {
        taskList.Add(ReadAsyc(item));
    }
    Task.Factory.ContinueWhenAll(taskList.ToArray(), i =>
    {
        string result = string.Empty;
        //獲取各個task返回的結(jié)果
        foreach (var item in i)
        {
            result += item.Result;
        }
        //倒序
        String content = new String(result.OrderByDescending(j => j).ToArray());
        Console.WriteLine("倒序結(jié)果:" + content);
    });
    Console.WriteLine("我是主線程,我不會被阻塞");
    Console.ReadKey();
}

//異步讀取
private static Task<string> ReadAsyc(string path)
{
    FileInfo info = new FileInfo(path);
    byte[] b = new byte[info.Length];
    FileStream fs = new FileStream(path, FileMode.Open);
    Task<int> task = Task<int>.Factory.FromAsync(fs.BeginRead, fs.EndRead, b, 0, b.Length, null, TaskCreationOptions.None);
    //返回當(dāng)前task的執(zhí)行結(jié)果
    return task.ContinueWith(i =>
    {
        return i.Result > 0 ? Encoding.Default.GetString(b) : string.Empty;
    }, TaskContinuationOptions.ExecuteSynchronously);
}

到此這篇關(guān)于.NET1.0異步編程模型(APM)的文章就介紹到這了。希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • .NET?Core讀取配置文件的方法

    .NET?Core讀取配置文件的方法

    這篇文章介紹了.NET?Core讀取配置文件的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2021-11-11
  • ASP.NET Core依賴關(guān)系注入

    ASP.NET Core依賴關(guān)系注入

    這篇文章介紹了ASP.NET Core中的依賴關(guān)系注入,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-04-04
  • ASP.NET Calendar日歷(日期)控件使用方法

    ASP.NET Calendar日歷(日期)控件使用方法

    本文主要介紹Calendar日歷控件的各個屬性以及舉例演示Calendar控件的具體使用方法,希望對大家有所幫助。
    2016-04-04
  • .Net結(jié)構(gòu)型設(shè)計(jì)模式之適配器模式(Adapter)

    .Net結(jié)構(gòu)型設(shè)計(jì)模式之適配器模式(Adapter)

    這篇文章介紹了.Net結(jié)構(gòu)型設(shè)計(jì)模式之適配器模式(Adapter),文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-05-05
  • 那些年,我還在學(xué)asp.net(一) 學(xué)習(xí)筆記

    那些年,我還在學(xué)asp.net(一) 學(xué)習(xí)筆記

    那些年到此,基本學(xué)習(xí)了前端的基本知識,那些年的第四課就是asp.net,當(dāng)然那時(shí)看了很多教程,比如說:天轟穿,當(dāng)然天轟穿說得比較多,如面向?qū)ο螅珻#知識,由于當(dāng)時(shí)上過C++,所以就沒有看這些,直接從asp.net開始,主要是學(xué)習(xí)一下asp.net用到的一些基本控件
    2012-03-03
  • MSMQ微軟消息隊(duì)列詳解

    MSMQ微軟消息隊(duì)列詳解

    本文詳細(xì)講解了MSMQ微軟消息隊(duì)列,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-01-01
  • ASP.NET?Core中間件用法與官方常用中間件介紹

    ASP.NET?Core中間件用法與官方常用中間件介紹

    這篇文章介紹了ASP.NET?Core中間件用法與官方常用中間件,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-03-03
  • IIS7 應(yīng)用程序池的 托管管道模式與集成模式小結(jié)

    IIS7 應(yīng)用程序池的 托管管道模式與集成模式小結(jié)

    而 IIS 7 完全整合 .NET 之后,架構(gòu)的處理順序有了很大的不同(如下圖),最主要的原因就是 ASP.NET 從 IIS 插件(ISAPI extension)的角色,進(jìn)入了 IIS 核心,而且也能以 ASP.NET 模塊負(fù)責(zé)處理 IIS 7 的諸多類型要求。
    2011-02-02
  • WPF框架Prism中導(dǎo)航Navigation用法介紹

    WPF框架Prism中導(dǎo)航Navigation用法介紹

    這篇文章介紹了WPF框架Prism中導(dǎo)航Navigation的用法,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-02-02
  • 一步步打造漂亮的新聞列表(無刷新分頁、內(nèi)容預(yù)覽)第二步

    一步步打造漂亮的新聞列表(無刷新分頁、內(nèi)容預(yù)覽)第二步

    由于我們僅僅是項(xiàng)目中的一個小部分,但也差不多按照以上的順序進(jìn)行開發(fā),這是一個良好的習(xí)慣。我們將概要設(shè)計(jì)和詳細(xì)設(shè)計(jì)放在一起。
    2010-07-07

最新評論