个人资料

跳过导航链接首页 > 博客列表 > 博客正文

使用Task以及async/await关键字进行异步等待

分类:

系列目录:

0.从delegete委托开始说起

1.委托和事件绑定

2.泛型委托

3.委托和多线程

4.委托和async/await异步等待


NET的线程池管理是很复杂的一套东西,使用Task对线程进行友好的访问是很必要。Task在MSDN上有详细的介绍:https://msdn.microsoft.com/zh-cn/library/system.threading.tasks.task.aspx 如果看了前面介绍泛型委托会有帮助理解Task任务.

这里简单介绍一些简单的Task使用方式.

Task用于构造那些耗时运算,例如网络连接类等。观察下面的代码:

namespace Turtual
{
    public class AboutTask
    {
         
        public  AboutTask()
        {
            // 这里虽然没有await,但Task是开辟新线程的,因此不会阻塞UI
            string result =GetResource("url","content=1").Result;
            // 主线程会直接继续,此时result是空的,不可用,因为Task还没有执行完毕
        }
 
        async void Dowork()
        {
            //如果想要等待任务完成,必须使用await/async关键字
            string result = await GetResource("url", "content=1");
            //会等待Task执行完成result,此时Result有值可以使用
        }
        //一个典型的任务方法
        public async Task<string> GetResource(string url, string para)
        {
            //模拟一个耗时操作
            string InfoUrl = "http://cn.bing.com/HPImageArchive.aspx?idx=0&n=1";
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(InfoUrl);
            request.Method = "GET"; request.ContentType = "text/html;charset=UTF-8";
            string XmlString;
            using (WebResponse response = await request.GetResponseAsync())
            {
                Stream myResponseStream = response.GetResponseStream();
                using (StreamReader myStreamReader = new StreamReader(myResponseStream, Encoding.UTF8))
                {
                    XmlString = myStreamReader.ReadToEnd();
                }
            }
            return XmlString;
        }
    }
}

上面的代码显示了Task任务简单的应用,Task使得整个过程可控,代码简洁而优美.刚接触Task语法我们自己不一定会写那些那些可等待的任务,但是需要学会使用系统的提供的可等待的方法,从上面的例子中我们可以看到这个过程并不难,甚至超出了以往的体验,拥抱Task以及await/async异步关键字.我刚开始有个疑惑,await/async异步关键字成对出现,await是等待的意思,那不是阻塞线程执行了么,其实从委托一路看过来就会明白,无论是否等待Task一定是新开线程或者回收旧线程,不会阻塞主线程.使用await的好处就是,如果需要使用异步的执行结果,那就需要等待.否则就不用.一般情况下,能用await就尽量使用await.在windows10通用应用里面所有的对话框是异步操作的,下面看看UWP中典型的弹出对话框是怎么使用await的吧!

//登陆
private async void LoginButton_Click(object sender, RoutedEventArgs e)
{
 
    if (App.IsLogin == false)
    {
        LoginDialog login = new LoginDialog();
        await login.ShowAsync();
        switch (login.Result)
        {
            case SignInResult.SignInOK:
                App.IsLogin = true;
                App.username = login.username;
                App.password = login.password;
                //(sender as AppBarButton).Label = "上传";
                await GetCloudFiles();//加载云数据
                break;
            case SignInResult.SignInFail:
                MessageDialog popup = new MessageDialog(AppResources.GetString("LoginFailed"));
                await popup.ShowAsync();
                break;
            case SignInResult.SignInCancel:
                break;
            case SignInResult.Nothing:
                break;
            default:
                break;
        }
    }
    else
    {
        MessageDialog md = new MessageDialog(AppResources.GetString("LoginSuccess"));
        await md.ShowAsync();
    }
 
 
}


使用了await方法,调用登陆对话框弹出,此时下面的代码都在等await结束,才能执行.在自定义的用户控件上面,使用远程的登陆Task.

namespace EasyNote
{
  
    public enum SignInResult
    {
        SignInOK,
        SignInFail,
        SignInCancel,
        Nothing
    }
  
    public sealed partial class LoginDialog : ContentDialog,INotifyPropertyChanged
    {
        private bool _Isbusy=false;
 
        public bool IsBusy
        {
            get { return _Isbusy; }
            set { SetProperty(ref _Isbusy,value); }
        }
 
        public SignInResult Result { get; private set; }
 
        public string username;
        public string password;
 
        //实现INotify接口------------------------------------
        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
        private void OnPropertyChanged([CallerMemberName] string propertyName = "")
        {
            this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
        private bool SetProperty<T>(ref T storage, T value, [CallerMemberName] String propertyName = null)
        {
            if (object.Equals(storage, value)) return false;
            storage = value;
            this.OnPropertyChanged(propertyName);
            return true;
        }
        //设置
        public UserSetting ClientSetting=new UserSetting();
        //属性
 
        public bool? SaveUserName
        {
            get
            {
                return ClientSetting.SaveUserName;
            }
            set { ClientSetting.SaveUserName = (bool)value; NotifyPropertyChanged(); }
        }
        private string _UserName;
        public string UserName
        {
            get
            {
                if (_UserName==null)
                {
                    _UserName = ClientSetting.UserName;
                }
                return _UserName;
            }
            set
            {
                if (SaveUserName!=false)
                {
                    ClientSetting.UserName = value;
                }
                _UserName = value;
                NotifyPropertyChanged();
                
            }
        }
        public string _PassWord;
        public string PassWord
        {
            get
            {
                if (_PassWord == null)
                {
                    _PassWord = ClientSetting.PassWord;
                }
                return _PassWord;
            }
            set
            {
                if (SaveUserName != false)
                {
                    ClientSetting.PassWord = value;
                }
                _PassWord = value;
                NotifyPropertyChanged();
 
            }
        }
 
        public LoginDialog()
        {
            this.InitializeComponent();
            //保存的设置
        }
        //登陆
        private async void ContentDialog_PrimaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args)
        {
            ContentDialogButtonClickDeferral deferral = args.GetDeferral();
 
            if (string.IsNullOrEmpty(userNameTextBox.Text))
            {
                args.Cancel = true;
                errorTextBlock.Text = "User name is required.";
            }
            else if (string.IsNullOrEmpty(passwordTextBox.Password))
            {
                args.Cancel = true;
                errorTextBlock.Text = "Password is required.";
            }
            await Login();
 
            deferral.Complete();
        }
 
 
        public async Task Login()
        {
            IsBusy = true;
 
            username = userNameTextBox.Text;
            password = passwordTextBox.Password;
            notecloud.EasyNoteCloudSoapClient client = new notecloud.EasyNoteCloudSoapClient();
            if ((await client.LoginAsync(username, password)))
            {
                this.Result = SignInResult.SignInOK;
            }
            else
            {
                this.Result = SignInResult.SignInFail;
            }
 
            IsBusy = false;
        }
        //取消
        private void ContentDialog_SecondaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args)
        {
            this.Result = SignInResult.SignInCancel;
        }
 
    }
}


上面的代码有趣的地方在于定义了一个IsBusy属性,并且使用了数据绑定绑定到界面的ProgressRing的IsActive属性,在Task执行过程中,进度环会告诉用户现在正忙.这就很实用了.


水平有限,如有错误,还请指正!(系列结束,觉得又烂尾了,(*^_^*))




songshizhao
最初发表2018/6/14 22:59:37 最近更新2018/6/14 22:59:37 4042
为此篇作品打分
10
   评论