Visual C#使用async和await进行异步编程

 在Visual Studio发布以来,新增了大量的功能,其中最让我感到欣喜的是C#新增的利用async标识符和await相结合使用进行异步编程,当然,遗憾的是,此功能只支持WinForm和WPF程序。

    使用 async 功能,您可以调用异步方法,而不定义持续性任务或通过多个方法或 lambda 表达式拆分代码。其实,仔细想想,其底层应该是封装了开辟新线程、调用和回调的操作!

    回想下,在先前的WinForm和WPF的同步编程,比如我们在当前UI下进行一个非常耗时的操作的时候,窗体的表现是不能随意拖动和关闭的,必须等待当前的操作完成之后,才能执行其他的操作,给用户的体验非常差。在以前的版本中,要实现异步操作,必须手动去启动窗体的UI线程允许跨进程调用的开关,并且把需要进行异步操作的代码写在一个委托中,然后手动的去新开线程,来完成异步的操作。

    然后,新版的Visual C#封装了这些麻烦的操作,让我们进行异步编程变得非常的简单。只需要利用async和await相结合使用,就可以轻松的异步编程。

    在下面的两个例子中,将详细的讲述如何利用async和await来进行异步编程。

    第一个例子,是一个简单的WPF程序,其主要功能是异步去请求几个URL,并得到这些资源的字符个数,然后输出在相应的文本框中。

    新建一个WPF应用程序,添加一个按钮和文本框,文本框多行显示。给按钮注册一个异步的Click方法。标志按钮的Click事件是一个异步方法,只需要添加标示符async。

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

            await SumPageSizesAsync();

            Task sumTask = SumPageSizesAsync();
            await sumTask;

            //上面的两句话等价于: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组件。

 

转载于:https://my.oschina.net/dyg540/blog/84612

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值