同步請求資源

請求msdn上的一個頁面計算頁面大小

大數(shù)據(jù)培訓,云培訓,數(shù)據(jù)挖掘培訓,云計算培訓,高端軟件開發(fā)培訓,項目經(jīng)理培訓

static void Main(string[] args)
{    string url = "https://docs.microsoft.com/zh-cn/dotnet/core/api/system";    try
    {
        WebRequest request = WebRequest.Create(url);
        WebResponse response = request.GetResponse();        using (var reader = new StreamReader(response.GetResponseStream()))
        {            string text = reader.ReadToEnd();
            Console.WriteLine(FormatBytes(text.Length));
        }
    }    catch (WebException e)
    {
    }    catch (IOException e)
    {
    }    catch (NotSupportedException e)
    {
    }
}static string FormatBytes(long bytes)
{    string[] magnitudes = new string[] { "GB", "MB", "KB", "Bytes" };    long max = (long)Math.Pow(1024, magnitudes.Length);    var t1 = magnitudes.FirstOrDefault(magnitude => bytes > (max /= 1024)) ?? "0 Bytes";    var t2 = ((decimal)bytes / (decimal)max);    return string.Format("{1:##.##} {0}", t1, t2).Trim();
}

大數(shù)據(jù)培訓,云培訓,數(shù)據(jù)挖掘培訓,云計算培訓,高端軟件開發(fā)培訓,項目經(jīng)理培訓

Ctrl+F5輸出 

大數(shù)據(jù)培訓,云培訓,數(shù)據(jù)挖掘培訓,云計算培訓,高端軟件開發(fā)培訓,項目經(jīng)理培訓

閃爍兩下后

大數(shù)據(jù)培訓,云培訓,數(shù)據(jù)挖掘培訓,云計算培訓,高端軟件開發(fā)培訓,項目經(jīng)理培訓

這里對資源的請求都是同步的,通俗易懂點就是一個步驟一個步驟的執(zhí)行,任何一個步驟耗時較長都會阻塞上下文線程(這里就是主線程)

使用C#5.0異步請求資源

大數(shù)據(jù)培訓,云培訓,數(shù)據(jù)挖掘培訓,云計算培訓,高端軟件開發(fā)培訓,項目經(jīng)理培訓

static void Main(string[] args)
{    string url = "https://docs.microsoft.com/zh-cn/dotnet/core/api/system";
    Task task = WriteWebRequestSizeAsync(url);    while (!task.Wait(100))
    {
        Console.Write(".");
    }
}static async Task WriteWebRequestSizeAsync(string url)
{    try
    {
        WebRequest request = WebRequest.Create(url);
        WebResponse response = await request.GetResponseAsync();        using (var reader = new StreamReader(response.GetResponseStream()))
        {            string text = await reader.ReadToEndAsync();
            Console.WriteLine(FormatBytes(text.Length));
        }
    }    catch (WebException)
    {

    }    //省略了一些catch塊}

大數(shù)據(jù)培訓,云培訓,數(shù)據(jù)挖掘培訓,云計算培訓,高端軟件開發(fā)培訓,項目經(jīng)理培訓

 

這種寫法在MVC中早就熟悉了,但是原理確不是很清楚,只知道這樣不會阻塞UI,async方法會創(chuàng)建一個新的線程執(zhí)行,await會阻塞上下文線程,一知半解隱藏著很可怕定時炸彈!

TPL異步調用

大數(shù)據(jù)培訓,云培訓,數(shù)據(jù)挖掘培訓,云計算培訓,高端軟件開發(fā)培訓,項目經(jīng)理培訓

static void Main(string[] args)
{    string url = "https://docs.microsoft.com/zh-cn/dotnet/core/api/system";
    Task task = WriteWebRequestSizeAsync(url);    try
    {        while (!task.Wait(100))
        {
            Console.Write(".");
        }
    }    catch (AggregateException excetion)
    {
        excetion = excetion.Flatten();        try
        {
            excetion.Handle(innerExcetion =>
            {
                ExceptionDispatchInfo.Capture(excetion.InnerException).Throw();                return true;
            });
        }        catch (WebException ex)
        {

        }        //省略了一些catch塊    }
}static Task WriteWebRequestSizeAsync(string url)
{
    StreamReader reader = null;
    WebRequest request = WebRequest.Create(url);
    Task task = request.GetResponseAsync()
        .ContinueWith(antecedent =>
        {
            WebResponse response = antecedent.Result;
            reader = new StreamReader(response.GetResponseStream());            return reader.ReadToEndAsync();
        })
        .Unwrap()
        .ContinueWith(antecedent =>
        {            if (null != reader)
                reader.Dispose();            string text = antecedent.Result;

            Console.WriteLine(FormatBytes(text.Length));
        });    return task;
}

大數(shù)據(jù)培訓,云培訓,數(shù)據(jù)挖掘培訓,云計算培訓,高端軟件開發(fā)培訓,項目經(jīng)理培訓

 

這個寫法是在沒有C#5.0之前,異步請求資源就是這么完成的,乍一看非常復雜,但是比較一下上面一種寫法,它似乎是思路清晰的

1.request.GetResponseAsync創(chuàng)建一個任務等待msdn服務器的響應

2.拿到這個響應后,獲得響應流,將流轉為字符串

3.接下來是Unwrap,這個應該是最難理解的了,實際上只有加上這句話以ContinueWith的思路寫下去,下一步就是直接拿string了

4.最后流已經(jīng)轉為字符串了,我們做個簡單的計算就行了

Unwrap的奧義

public static Task<TResult> Unwrap<TResult>(this Task<Task<TResult>> task);

從簽名上來看,它是一個Task<Task<TResult>>類型的拓展方法,任務,帶返回值的任務...暈了,別急,等下慢慢來

回到剛剛代碼看看有什么端倪

1.GetResponseAsync()創(chuàng)建(意思和返回值一樣,為了區(qū)分任務返回值)一個任務,具體類型Task<WebResponse>,這個任務結束返回一個WebResponse

 大數(shù)據(jù)培訓,云培訓,數(shù)據(jù)挖掘培訓,云計算培訓,高端軟件開發(fā)培訓,項目經(jīng)理培訓

 2.第一個ContinueWith調用者是一個Task<WebResponse>,形參是一個委托接受一個Task<WebReponse>,返回一個Task<string>(通過reader.ReadToEndAsync可以理解),返回值是一個Task沒有問題,問題在它的泛型參數(shù)是什么,首先此處ContinueWith中的代碼是在一個新的工作線程中運行的,我們把它想象成主線程(只是相對的一個環(huán)境),'主線程'要完成什么任務呢?,他要拿Task<WebResponse>的執(zhí)行結果WebResponse(雖然這里可以肯定這個任務已經(jīng)執(zhí)行完成了,但是微軟沒有這么做),然后根據(jù)這個WebResponse在創(chuàng)建一個Task<string>,作為當前工作線程的返回值

大數(shù)據(jù)培訓,云培訓,數(shù)據(jù)挖掘培訓,云計算培訓,高端軟件開發(fā)培訓,項目經(jīng)理培訓

 3.現(xiàn)在問題來了,我們得到的是一個Task<Task<string>>,我們可以通過調用兩次Result獲取這個string,但是在這個ContinueWith塊中,只能保證外層的Task是執(zhí)行完成的,所以第二個Result或阻塞上下文線程

大數(shù)據(jù)培訓,云培訓,數(shù)據(jù)挖掘培訓,云計算培訓,高端軟件開發(fā)培訓,項目經(jīng)理培訓

Task task = request.GetResponseAsync()
    .ContinueWith(antecedent =>
    {
        WebResponse response = antecedent.Result;
        reader = new StreamReader(response.GetResponseStream());        return reader.ReadToEndAsync();
    })
    .ContinueWith(antecedent =>
    {        var resTask = antecedent.Result;        var resString = resTask.Result;        if (null != reader)
        {            string text = resString;
            Console.WriteLine(FormatBytes(text.Length));
        }
    });

大數(shù)據(jù)培訓,云培訓,數(shù)據(jù)挖掘培訓,云計算培訓,高端軟件開發(fā)培訓,項目經(jīng)理培訓

 

 4.這個時候再回到Unwarp(),它就是脫去了外層的Task,得到的內層的任務上下文線程,并把它作為延續(xù)任務的主線程

大數(shù)據(jù)培訓,云培訓,數(shù)據(jù)挖掘培訓,云計算培訓,高端軟件開發(fā)培訓,項目經(jīng)理培訓

 5.這里取出的Result就是string,計算并輸出

 大數(shù)據(jù)培訓,云培訓,數(shù)據(jù)挖掘培訓,云計算培訓,高端軟件開發(fā)培訓,項目經(jīng)理培訓

法器ILSpy

通過ILSpy反編譯后可以逐步查到,Unwarp()實際上就是保證了內層任務開始執(zhí)行,并返回一個內層任務的執(zhí)行環(huán)境(上下文線程)

大數(shù)據(jù)培訓,云培訓,數(shù)據(jù)挖掘培訓,云計算培訓,高端軟件開發(fā)培訓,項目經(jīng)理培訓

大數(shù)據(jù)培訓,云培訓,數(shù)據(jù)挖掘培訓,云計算培訓,高端軟件開發(fā)培訓,項目經(jīng)理培訓

 

http://www.cnblogs.com/cheesebar/p/6553310.html