C#異步編程のawait和async關鍵字來寫異步程序

1、await和async關鍵字web

.Net平臺不斷推出了新的異步編程模型,在.net4.5中加入了關鍵字await和async,顧名思義,await是指方法執行可等待,便可掛起直到有結果(不是必須當即佔用主進程),async標明此方法是異步方法編程

await 運算符在異步方法應用於任務,以掛起執行方法,直到所等待的任務完成。 任務表示正在進行的工做。windows

在其中使用 await 的異步方法必須經過 async 關鍵字進行修改。 使用 async 修飾符定義而且一般包含一個或多個 await 表達式的這類方法稱爲異步方法。app

2、分析關鍵字結構及語法異步

     先解析一下專業名詞:
     同步方法:一個程序調用某個方法,等到其執行完成以後才進行下一步操做。這也是默認的形式。
     異步方法:一個程序調用某個方法,在處理完成以前就返回該方法。經過 async/await 咱們就能夠實現這種類型的方法。
 
     async/await 結構可分紅三部分:
     (1)調用方法:該方法調用異步方法,而後在異步方法執行其任務的時候繼續執行;
     (2)異步方法:該方法異步執行工做,而後馬上返回到調用方法;
     (3)await 表達式:用於異步方法內部,指出須要異步執行的任務。一個異步方法能夠包含多個 await 表達式(不存在 await 表達式的話 IDE 會發出警告)。
     異步方法:在執行完成前當即返回調用方法,在調用方法繼續執行的過程當中完成任務。
 
     語法分析:
     (1)關鍵字:方法頭使用 async 修飾。
     (2)要求:包含 N(N>0) 個 await 表達式(不存在 await 表達式的話 IDE 會發出警告),表示須要異步執行的任務。
     (3)返回類型:只能返回 3 種類型(void、Task 和 Task<T>)。Task 和 Task<T> 標識返回的對象會在未來完成工做,表示調用方法和異步方法能夠繼續執行。
     (4)參數:數量不限,但不能使用 out 和 ref 關鍵字。
     (5)命名約定:方法後綴名應以 Async 結尾。
     (6)其它:匿名方法和 Lambda 表達式也能夠做爲異步對象;async 是一個上下文關鍵字;關鍵字 async 必須在返回類型前。

3、異步調用httpasync

        private async void startButton_Click(object sender, RoutedEventArgs e)
        {
            // Disable the button until the operation is complete.
            startButton.IsEnabled = false;

            resultsTextBox.Clear();

            // One-step async call.
            await SumPageSizesAsync();

            //// Two-step async call.
            //Task sumTask = SumPageSizesAsync();
            //await sumTask;

            resultsTextBox.Text += "\r\nControl returned to startButton_Click.\r\n";

            // Reenable the button in case you want to run the operation again.
            startButton.IsEnabled = true;
        }


        private async Task SumPageSizesAsync()
        {
            // Declare an HttpClient object.
            HttpClient client = new HttpClient();

            // Make a list of web addresses.
            List<string> urlList = SetUpURLList();

            var total = 0;

            foreach (var url in urlList)
            {
                // GetByteArrayAsync returns a task. At completion, the task
                // produces a byte array.
                byte[] urlContents = await client.GetByteArrayAsync(url);

                // The following two lines can replace the previous assignment statement.
                //Task<byte[]> getContentsTask = client.GetByteArrayAsync(url);
                //byte[] urlContents = await getContentsTask;
                DisplayResults(url, urlContents);

                // Update the total.
                total += urlContents.Length;
            }

            // Display the total count for all of the websites.
            resultsTextBox.Text +=
                string.Format("\r\n\r\nTotal bytes returned:  {0}\r\n", total);
        }


        private List<string> SetUpURLList()
        {
            List<string> urls = new List<string> 
            { 
                "http://msdn.microsoft.com/library/windows/apps/br211380.aspx",
                "http://msdn.com",
                "http://msdn.microsoft.com/en-us/library/hh290136.aspx",
                "http://msdn.microsoft.com/en-us/library/ee256749.aspx",
                "http://msdn.microsoft.com/en-us/library/hh290138.aspx",
                "http://msdn.microsoft.com/en-us/library/hh290140.aspx",
                "http://msdn.microsoft.com/en-us/library/dd470362.aspx",
                "http://msdn.microsoft.com/en-us/library/aa578028.aspx",
                "http://msdn.microsoft.com/en-us/library/ms404677.aspx",
                "http://msdn.microsoft.com/en-us/library/ff730837.aspx"
            };
            return urls;
        }


        private void DisplayResults(string url, byte[] content)
        {
            // Display the length of each website. The string format 
            // is designed to be used with a monospaced font, such as
            // Lucida Console or Global Monospace.
            var bytes = content.Length;
            // Strip off the "http://".
            var displayURL = url.Replace("http://", "");
            resultsTextBox.Text += string.Format("\n{0,-58} {1,8}", displayURL, bytes);
        }

 

4、其餘示例異步編程

public class MyClass  
{  
    public MyClass()  
    {  
        DisplayValue(); //這裏不會阻塞  
        System.Diagnostics.Debug.WriteLine("MyClass() End.");  
    }  
    public Task<double> GetValueAsync(double num1, double num2)  
    {  
        return Task.Run(() =>  
        {  
            for (int i = 0; i < 1000000; i++)  
            {  
                num1 = num1 / num2;  
            }  
            return num1;  
        });  
    }  
    public async void DisplayValue()  
    {  
        double result = await GetValueAsync(1234.5, 1.01);//此處會開新線程處理GetValueAsync任務,而後方法立刻返回  
        //這以後的全部代碼都會被封裝成委託,在GetValueAsync任務完成時調用  
        System.Diagnostics.Debug.WriteLine("Value is : " + result);  
    }  
}  

要執行異步操做的方法用async標記,調用方法時用await標記,被異步調用的方法返回值用<task>修飾。url

實際執行代碼:spa

public void DisplayValue()  
{  
    System.Runtime.CompilerServices.TaskAwaiter<double> awaiter = GetValueAsync(1234.5, 1.01).GetAwaiter();  
    awaiter.OnCompleted(() =>  
        {  
            double result = awaiter.GetResult();  
            System.Diagnostics.Debug.WriteLine("Value is : " + result);  
        });  
} 

如下爲某大神寫的靜態類,能夠將通常方法轉化爲異步調用:.net

public static class TaskAsyncHelper  
02.{  
03.    /// <summary>  
04.    /// 將一個方法function異步運行,在執行完畢時執行回調callback  
05.    /// </summary>  
06.    /// <param name="function">異步方法,該方法沒有參數,返回類型必須是void</param>  
07.    /// <param name="callback">異步方法執行完畢時執行的回調方法,該方法沒有參數,返回類型必須是void</param>  
08.    public static async void RunAsync(Action function, Action callback)  
09.    {  
10.        Func<System.Threading.Tasks.Task> taskFunc = () =>  
11.        {  
12.            return System.Threading.Tasks.Task.Run(() =>  
13.            {  
14.                function();  
15.            });  
16.        };  
17.        await taskFunc();  
18.        if (callback != null)  
19.            callback();  
20.    }  
21.  
22.    /// <summary>  
23.    /// 將一個方法function異步運行,在執行完畢時執行回調callback  
24.    /// </summary>  
25.    /// <typeparam name="TResult">異步方法的返回類型</typeparam>  
26.    /// <param name="function">異步方法,該方法沒有參數,返回類型必須是TResult</param>  
27.    /// <param name="callback">異步方法執行完畢時執行的回調方法,該方法參數爲TResult,返回類型必須是void</param>  
28.    public static async void RunAsync<TResult>(Func<TResult> function, Action<TResult> callback)  
29.    {  
30.        Func<System.Threading.Tasks.Task<TResult>> taskFunc = ()=>  
31.            {  
32.                return System.Threading.Tasks.Task.Run(()=>  
33.                    {  
34.                        return function();  
35.                    });  
36.            };  
37.        TResult rlt = await taskFunc();  
38.        if(callback != null)  
39.            callback(rlt);  
40.    }  
41.}  

 

async用來修飾方法,代表這個方法是異步的,聲明的方法的返回類型必須爲:void,Task或Task<TResult>。

await必須用來修飾Task或Task<TResult>,並且只能出如今已經用async關鍵字修飾的異步方法中。一般狀況下,async/await成對出現纔有意義,

上面提到task.wait可讓主線程等待後臺線程執行完畢,await和wait相似,一樣是等待,等待Task<string>.Run()開始的後臺線程執行完畢,不一樣的是await不會阻塞主線程

歡迎加入qq羣交流:568055323

相關文章
相關標籤/搜索