Visual C#使用async和await進行異步編程

 在Visual Studio發佈以來,新增了大量的功能,其中最讓我感到欣喜的是C#新增的利用async標識符和await相結合使用進行異步編程,固然,遺憾的是,此功能只支持WinForm和WPF程序。 web

    使用 async 功能,您能夠調用異步方法,而不定義持續性任務或經過多個方法或 lambda 表達式拆分代碼。其實,仔細想一想,其底層應該是封裝了開闢新線程、調用和回調的操做! 編程

    回想下,在先前的WinForm和WPF的同步編程,好比咱們在當前UI下進行一個很是耗時的操做的時候,窗體的表現是不能隨意拖動和關閉的,必須等待當前的操做完成以後,才能執行其餘的操做,給用戶的體驗很是差。在之前的版本中,要實現異步操做,必須手動去啓動窗體的UI線程容許跨進程調用的開關,而且把須要進行異步操做的代碼寫在一個委託中,而後手動的去新開線程,來完成異步的操做。 windows

    而後,新版的Visual C#封裝了這些麻煩的操做,讓咱們進行異步編程變得很是的簡單。只須要利用async和await相結合使用,就能夠輕鬆的異步編程。 app

    在下面的兩個例子中,將詳細的講述如何利用async和await來進行異步編程。 異步

    第一個例子,是一個簡單的WPF程序,其主要功能是異步去請求幾個URL,並獲得這些資源的字符個數,而後輸出在相應的文本框中。 async

    新建一個WPF應用程序,添加一個按鈕和文本框,文本框多行顯示。給按鈕註冊一個異步的Click方法。標誌按鈕的Click事件是一個異步方法,只須要添加標示符async。 異步編程

        private async void startButton_Click(object sender, RoutedEventArgs e)
        {
            resultsTextBox.Clear();
this

            await SumPageSizesAsync(); url

            Task sumTask = SumPageSizesAsync();
            await sumTask;
spa

            //上面的兩句話等價於:await SumPageSizesAsync();

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

        private async Task SumPageSizesAsync()
        {
            //.Net Framework4.5中新增了一個新的類HttpClient,這個類封裝異步web操做,很是的牛B

            //固然咱們也能夠用傳統的WebRequest和HttpWebRequest類。
            HttpClient client = new HttpClient();

            List<string> urlList = SetUpURLList();

            var total = 0;

            foreach (var url in urlList)
            {.
                byte[] urlContents = await client.GetByteArrayAsync(url);

                //上面的一句話等價於下面的兩句話
                //Task<byte[]> getContentsTask = client.GetByteArrayAsync(url);
                //byte[] urlContents = await getContentsTask;
                DisplayResults(url, urlContents);

                total += urlContents.Length;
            }

            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);
        }

 有關HttpClient和Task、Task<TResult>請參考MSDN。

編譯WPF應用程序,在程序異步執行請求操做的時候,你能夠隨意的拖動窗口或者隨時均可以關閉窗口,是否是以爲很方便,體驗也很爽。想了解更詳細的信息,告訴你一個祕籍,趕忙看MSDN,而且撞上windows8和Visual Studio2012開始你的奇妙之旅吧。

 

       第二例子是文件I/O的異步操做,下面的例子包括了異步讀取操做、異步拷貝操做、異步寫操做。更多地文件I/O異步操做,建議你放看MSDN。

       新建一個WinForm程序,添加三個按鈕,來分別執行異步讀取操做、異步拷貝操做、異步寫操做。

       在上面的WPF例子中,講述瞭如何爲按鈕註冊一個異步事件。就是用async標示Click事件。

       

       //異步讀
        private async void btnReadAsync_Click(object sender, EventArgs e)
        {
            string sourceDir = @"C:\個人文件夾";
            this.txtContentsByReadAsync.Clear();
            foreach (string item in Directory.EnumerateFiles(sourceDir))
            {
                string fileContents="";
                using (StreamReader sr=File.OpenText(item))
                {
                    fileContents= sr.ReadToEnd();
                }
                using (FileStream stream=File.Open(item, FileMode.Open))
                {
                    byte[] buffer=new byte[stream.Length];
                    int num= await stream.ReadAsync(buffer, 0, buffer.Length);
                    this.txtContentsByReadAsync.Text += string.Format("讀取了{0}個字節\r\n,文件的內容爲:\r\n{1}", num.ToString(), fileContents);
                }
            }
        }

        //異步拷貝

        private async void btnCopyToAsync_Click(object sender, EventArgs e)
        {
            string startDir = @"C:\個人文件夾";
            string destinationDir = @"C:\個人文件夾\新建文件夾\";
            foreach (string item in Directory.EnumerateFiles(startDir))
            {
                using (FileStream fileStream=File.Open(item, FileMode.Open))
                {
                    using (FileStream Stream=File.Create(destinationDir+item.Substring(item.LastIndexOf('\\'),item.Length-item.LastIndexOf('\\'))))
                    {
                        await fileStream.CopyToAsync(Stream);
                    }
                }
            }
        }

        //異步寫

        private async void btnWriteAsync_Click(object sender, EventArgs e)
        {
            string sourceDir = @"C:\個人文件夾";
            foreach (string item in Directory.EnumerateFiles(sourceDir))
            {
                using (StreamReader reader=File.OpenText(item))
                {
                    using (StreamWriter writer=File.CreateText(sourceDir+"\\"+"新建文件夾"+"\\"+"複製文件"+item.Substring(item.LastIndexOf('\\')+1)))
                    {
                        await CopyFilesAsync(reader, writer);
                    }
                }
            }
        }

        private async Task CopyFilesAsync(StreamReader reader, StreamWriter writer)
        {
            char[] buffer = new char[0x1000];
            int num;
            while ((num = await reader.ReadAsync(buffer, 0, buffer.Length)) != 0)
            {
                await writer.WriteAsync(buffer, 0, num);
            }
        }

      從上面的例子中能夠看出,進行文件的異步I\O操做已經變得如此簡單。

      注意,要使用await異步編程,代碼必須放在aysnc標識符標識的異步方法內部。對於控件的事件,只須要用async來標識便可。對於普通的方法,若是方法的返回值爲空或者null的時候,用async和task一塊兒標識該方法是無返回值的方法,對於返回泛型類型的方法來講,用async和task<T>來同時標誌方法是異步方法,其中T爲返回的類型。

     上面的WPF例子用到了.Net Framework提供的新的類HttpClient,要使用這個類,程序中必須引用組件:

      System.Net.Http組件。

相關文章
相關標籤/搜索