<em id="3iliw"></em>
  • <progress id="3iliw"></progress>
  • <tbody id="3iliw"><pre id="3iliw"></pre></tbody><dd id="3iliw"><noscript id="3iliw"></noscript></dd>

    <progress id="3iliw"></progress>

    杭州.net培訓
    達內杭州.net培訓中心

    13175137725

    異步編程你必須了解的!

    • 時間:2019-01-17 10:00
    • 發布:轉載
    • 來源:網絡

    異步編程是程序設計的重點也是難點,還記得在剛開始接觸.net的時候,看的是一本c#的Winform實例教程,上面大部分都是教我們如何使用Winform的控件以及操作數據庫的實例,那時候做的基本都是數據庫的demo,數據量也不大,程序在執行的時候基本上不會出現阻塞的情況。隨著不斷的深入.net,也開始進入的實戰,在實際的項目,數據量往往都是比較大,特別是在大量的數據入庫以及查詢數據并進行計算的時候,程序的UI界面往往卡死在那里,發生了阻塞,這時候就需要對計算時間限制的過程進行異步處理,讓UI線程繼續相應用戶的操作,使得用戶體驗表現比較友好,同時正確的使用異步編程去處理計算限制的操作和耗時IO操作還能提升的應用程序的吞吐量及性能。由此可見,異步編程的重要性。

    異步編程在程序設計中也是非常復雜的,稍有不慎,就會使得你的應用程序變得不穩定,出現異常,甚至會奔潰。但是,比較幸運的是,.net提供非常方便的框架來進行異步編程,在我看來.net中實現異步有兩種方式,第一種是多線程的方式,第二種是使用異步函數,其實在異步函數中使用的還是多線程的技術。接下來就介紹在.net中如何使用多線程和異步函數來解決計算限制、耗時等這些不友好用戶體驗的問題。

    異步編程中比較關心,也是比較重要的技術點在于,1)當異步線程在工作完成時如何通知調用線程,2)當異步線程出現異常的時候該如何處理,3)異步線程工作的進度如何實時的通知調用線程。4)如何在調用線程中取消正在工作的異步線程,并進行回滾操作。

    一、異步函數模型

    c#中提供異步函數編程模式,只要是使用委托對象封裝的函數都可以實現該函數的異步調用,這是因為委托類型有BeginInvoke和EndInvoke這兩個方法來支持異步調用。

    下面給出一個例子來講解如何使用委托的來實現異步調用函數。

    classProgram

    {        publicdelegatevoidDoWork();        staticvoidMain(string[] args)

    {

    DoWork d =newDoWork(WorkPro);//no.1

    d.BeginInvoke(null,null);//no.2

    for(inti =0; i <100; i++)//no.3           {

    Thread.Sleep(10);//主線程需要做的事           }

    Console.WriteLine("主線程done");

    Console.ReadKey();

    }        publicstaticvoidWorkPro()

    {            //做一些耗時的工作

    Thread.Sleep(2000);

    Console.WriteLine("異步調用結束");

    }

    }

    程序定義了一個DoWork類型無參無返回值的的委托類型,no.1用WorkPro方法實例化一個DoWork類型的對象d ,no.2通過委托對象d的BeginInvoke(null,null)(下面將會詳細介紹BeginInvoke函數中兩個參數如何使用)來實現WorkPro函數的異步調用,這樣就使得no.3主線程所做的for循環和WorkPro函數可以同時執行,這樣使得程序的運行效率得到了大幅度的提升。如果程序是同步執行的話,假設WorkPro函數執行需要2秒,for需要1秒,總共執行時間就需要3秒,如果WorkPro是異步執行的話,那么整個程序執行完畢只需要2秒就夠了。

    ------

    上面這個例子只是簡單演示了如何通過委托來實現函數的異步調用,而沒有傳遞給該異步函數任何的參數,也不需要獲取該異步函數的結果。如果主線需要傳遞給該異步函數一個參數,并且還要在該異步函數執行完畢之后獲取其執行結果,那應該如何實現呢?

    classProgram

    {        publicdelegateintDoWord(intcount);        staticvoidMain(string[] args)

    {

    DoWord d =newDoWord(WorkPro);

    IAsyncResult r= d.BeginInvoke(1000,null,null);//no.1

    intresult= d.EndInvoke(r);//no.2           Console.WriteLine(result);            for(inti =0; i <100; i++)//no.3           {

    Thread.Sleep(10);//主線程需要做的事           }

    Console.WriteLine("主線程done");

    Console.ReadKey();

    }        publicstaticintWorkPro(intcount)

    {            intsum =0;            //做一些耗時的工作

    for(inti =0; i < count; i++)

    {

    sum += i;

    }            returnsum;        

    }

    我們已經把委托類型改為具有一個int類型的參數和int類型返回值。在這里解釋一下,每當你的編譯器發現定義了一個委托類型,就會對應的生成一個類型,并且該類型BeginInvoke方法的參數個數也是不同的,本例聲明的委托類型為:

    public delegate int DoWord(int count);

    實際生成的BeginInvoke原型為:IAsyncResult   BeginInvoke(int count, AsyncCallBack callback, object @object)

    在no.1處還是和第一個例子一樣調用委托,不同的是用IAsyncResult接口的變量接收了異步調用(并不是異步函數)的返回狀態,這是方便后面調用EndInvoke方法接受這個異步函數調用結果而使用的,也可以通過該參數查看異步函數執行的狀態,該接口有一個IsCompleted的屬性。在no.2處使用d.EndInvoke(r)來接受異步函數返回值的。必須指出的是,主線程在調用委托的EndInvoke(r)方法時,當異步函數沒有執行完畢的話,主線程會一直處于阻塞,等待異步函數執行完畢,獲取返回值之后才執行no.3的for循環。這樣就還會導致主線程處于阻塞狀態。

    理想的狀態的是,當異步函數調用完成之后,自動通知任務執行完成。當然委托也能夠做到,這就要使用BeginInvoke方法的后兩個參數啦。看下面這個例子。

    classProgram

    {        publicdelegateintDoWord(intcount);        staticvoidMain(string[] args)

    {

    DoWord d =newDoWord(WorkPro);

    IAsyncResult r= d.BeginInvoke(100,CallBack ,d);//no.1

    for(inti =0; i <100; i++)

    {

    Thread.Sleep(10);//主線程需要做的事           }

    Console.WriteLine("主線程done");

    Console.ReadKey();

    }        publicstaticintWorkPro(intcount)

    {            intsum =0;            //做一些耗時的工作

    for(inti =0; i < count; i++)

    {

    sum += i;

    Thread.Sleep(10);

    }            returnsum;        

    }

    publicstaticvoidCallBack(IAsyncResult r)

    {

    DoWord d = (DoWord)r.AsyncState;

    Console.WriteLine("異步調用完成,返回結果為{0}", d.EndInvoke(r));

    }

    }

    首先來解釋一下BeginInvoke方法的第二個參數是AsyncCallBack 類型的委托(回調函數),當該參數不為空,那么在異步函數執行完畢之后,會調用該委托;第三個參數Object 類型的,代表傳遞給回調函數的異步調用狀態。CallBack回調函數必須帶有一個IAsyncResult 類型的參數,通過這個參數可以在回調方法內部獲取異步調用的結果。在no.1出就給BeginInvoke函數傳遞了回調函數CallBack,和委托d,當異步數WorkPro執行完畢之后,就立即通知CallBack回調函數來顯示執行結果。這下主線程就不需要阻塞一直的等待異步函數的結果,大大的提升了程序的運行效率。在.net還提供許多類的BeinXXX()和EndXXX()的異步版本,比如文件的讀寫等,具體可以查閱相關的資料。

    二、多線程模型

    .net在System.Threading和System.Threading.Tasks這兩個命名空間中提供了Thread,ThreadPool,和Task三個類來處理多線程的問題,其中Thread是建立一個專用線程,ThreadPool是使用線程池中工作線程,而Task類是采用任務的方式,其內部也是使用線程池中的工作線程。本節只講Tread類和Tasks類的使用以及其優劣。

    1、Thread類

    Thread類的使用方法很簡單,它開辟的是一個專用線程,不是線程池中的工作線程,不由線程池去管理。該類提供4個重載版本,常見的使用前面兩個就好了。

    1)public Thread( ThreadStart start ):其中ThreadStart是一個無參無返回值的委托類型。

    2)public Thread( ParameterizedThreadStart start ):其中ParameterizedThreadStart 是一個帶有一個Object類型的參數,無返回值的委托類型。

    從Thread類提供了兩個構造函數可以看出,Thread類能夠異步調用無參無返回值的函數,也能夠異步調用帶一個Object類型的無返回值的函數。下面就給出一個例子簡單的演示一下如何使用Thread異步執行一個帶參數的函數。

    classProgram

    {        staticvoidMain(string[] args)

    {

    Thread t =newThread(WorkPro);//no.1

    t.IsBackground =true;//no.2

    t.Start(1000);//no.3       }        publicstaticvoidWorkPro(object t)

    {            //做一些耗時的工作 

    intcount=(int)t;            for(inti =0; i < count; i++)

    {

    Thread.Sleep(2000);

    }

    Console.WriteLine("任務處理完成");

    }

    }

    預約申請免費試聽課

    怕錢不夠?就業掙錢后再付學費!    怕學不會?從入學起,達內定制課程!     擔心就業?達內多家實踐企業供你挑選!

    上一篇:這些NETCore中的并發編程必須知道!
    下一篇:.NET Core 和 .NET Standard之間的關系
    • 掃碼領取資料

      回復關鍵字:視頻資料

      免費領取 達內課程視頻學習資料

    • 視頻學習QQ群

      添加QQ群:1143617948

      免費領取達內課程視頻學習資料

    Copyright ? 2018 Tedu.cn All Rights Reserved 京ICP備08000853號-56 京公網安備 11010802029508號 達內時代科技集團有限公司 版權所有

    選擇城市和中心
    江西省

    貴州省

    廣西省

    海南省

    国拍自产亚洲 2019国拍自产在线,国拍自产亚洲,国产a在线不卡 百度 好搜 搜狗
    <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <文本链> <文本链> <文本链> <文本链> <文本链> <文本链>