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组件。

相关文章
相关标签/搜索