C# 学习笔记 18.异步编程

1.何为异步编程

异步编程就是把耗时的操作放入一个单独的线程中处理,不要阻塞主线程,线程任务完成后

通知主线程。

2.同步的方法实现(ui会卡住)

 public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            textBox1.Text = "https://download.microsoft.com/download/2/0/E/20E90413-712F-438C-988E-FDAA79A8AC3D/dotnetfx35.exe";
        }

        private void button_down_Click(object sender, EventArgs e)
        {
            textBox2.Text = "下载中...";

            if (textBox1.Text == string.Empty)
            {
                MessageBox.Show("请先输入地址!");
                return;
            }
            DownLoadFile(textBox1.Text.Trim());
        }

        public void DownLoadFile(string url)
        {
            int buffer_size = 2048;
            byte[] buffer_read = new byte[buffer_size];
            string save_path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\dotnet.exe";

            FileStream file_stream = null;
            HttpWebResponse my_web_response = null;
            if(File.Exists(save_path))
            {
                File.Delete(save_path);
            }

            file_stream = new FileStream(save_path, FileMode.OpenOrCreate);
            try
            {
                HttpWebRequest my_http_web_requset = (HttpWebRequest)WebRequest.Create(url);

                if(my_http_web_requset != null)
                {
                    my_web_response = (HttpWebResponse)my_http_web_requset.GetResponse();
                    Stream response_stream = my_web_response.GetResponseStream();
                    int read_size = response_stream.Read(buffer_read, 0, buffer_size);
                    while (read_size >0)
                    {
                        file_stream.Write(buffer_read, 0, read_size);
                        read_size = response_stream.Read(buffer_read, 0, buffer_size);
                    }

                }
                textBox2.Text = "文件下载完成,文件大小为:" + file_stream.Length +
                    "下载的路径为:" + save_path;
            }
            catch(Exception e)
            {
                textBox2.Text = "下载中发生异常 异常信息为:" + e.Message;
            }
            finally
            {
                if(my_web_response != null)
                {
                    my_web_response.Close();
                }
                if(file_stream != null)
                {
                    file_stream.Close();
                }
            }

        }
    }

3.利用APM方法同步(Asynchronous Programming Mode)

  public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            textBox1.Text = "https://download.microsoft.com/download/2/0/E/20E90413-712F-438C-988E-FDAA79A8AC3D/dotnetfx35.exe";
        }
        private delegate string AsyncMethodCaller(string fileurl);

        SynchronizationContext sc;
        private void button_down_Click(object sender, EventArgs e)
        {
            textBox2.Text = "下载中...";
            button_down.Enabled = false;

            if (textBox1.Text == string.Empty)
            {
                MessageBox.Show("请先输入地址!");
                return;
            }
            sc = SynchronizationContext.Current;//获得调用线程同步的上下文对象
            AsyncMethodCaller method_caller = new AsyncMethodCaller(DownLoadFile);
            method_caller.BeginInvoke(textBox1.Text.Trim(),GetResult, null);

        }

        private  void GetResult(IAsyncResult result) //异步完成后调用
        {
            AsyncMethodCaller caller = (AsyncMethodCaller)((AsyncResult)result).AsyncDelegate;
            string return_string = caller.EndInvoke(result);
            sc.Post(ShowState, return_string);
        }
        private void ShowState(object result)
        {
            textBox2.Text = result.ToString();
            button_down.Enabled = true;
        }
        public string  DownLoadFile(string url)
        {
            int buffer_size = 2048;
            byte[] buffer_read = new byte[buffer_size];
            string save_path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\dotnet.exe";

            FileStream file_stream = null;
            HttpWebResponse my_web_response = null;
            if(File.Exists(save_path))
            {
                File.Delete(save_path);
            }

            file_stream = new FileStream(save_path, FileMode.OpenOrCreate);
            try
            {
                HttpWebRequest my_http_web_requset = (HttpWebRequest)WebRequest.Create(url);

                if(my_http_web_requset != null)
                {
                    my_web_response = (HttpWebResponse)my_http_web_requset.GetResponse();
                    Stream response_stream = my_web_response.GetResponseStream();
                    int read_size = response_stream.Read(buffer_read, 0, buffer_size);
                    while (read_size >0)
                    {
                        file_stream.Write(buffer_read, 0, read_size);
                        read_size = response_stream.Read(buffer_read, 0, buffer_size);
                    }

                }
                return string.Format("文件下载完成,文件大小为: {0}下载的路径为:{1}" + file_stream.Length, save_path);
               
            }
            catch(Exception e)
            {
                return string.Format( "下载中发生异常 异常信息为:{0}" ,e.Message);
            }
            finally
            {
                if(my_web_response != null)
                {
                    my_web_response.Close();
                }
                if(file_stream != null)
                {
                    file_stream.Close();
                }
            }

        }
    }

4.EAP Event-based Asynchronous pattern)

基于事件的异步模式

 

  public partial class Form1 : Form
    {
        private int download_size = 0;
        public string download_path = null;
        long total_size = 0;
        const int buffer_size = 2048;
        byte[] buffer_read = new byte[buffer_size];
        FileStream file_stream = null;
        HttpWebResponse my_web_response = null;

        public Form1()
        {
            InitializeComponent();
            textBox1.Text = "https://download.microsoft.com/download/2/0/E/20E90413-712F-438C-988E-FDAA79A8AC3D/dotnetfx35.exe";
            this.button_pause.Enabled = false;
            GetTotalSize();
            download_path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\"+Path.GetFileName(this.textBox1.Text.Trim());

            if(File.Exists(download_path))
            {
                FileInfo file_info = new FileInfo(download_path);
                download_size = (int)file_info.Length;
                progressBar1.Value = (int)((float)download_size / (float)total_size * 100); 
            }
            backgroundWorker1.WorkerReportsProgress = true;
            backgroundWorker1.WorkerSupportsCancellation = true;
        }
        private void GetTotalSize()
        {
            HttpWebRequest my_http_web_request = (HttpWebRequest)WebRequest.Create(textBox1.Text.Trim());
            HttpWebResponse response = (HttpWebResponse)my_http_web_request.GetResponse();
            total_size = response.ContentLength;
            response.Close();
        }
        private void button_down_Click(object sender, EventArgs e)
        {
            if(backgroundWorker1.IsBusy != true)
            {
                backgroundWorker1.RunWorkerAsync();

                file_stream = new FileStream(download_path, FileMode.OpenOrCreate);
                file_stream.Seek(download_size, SeekOrigin.Begin);
                this.button_down.Enabled = false;
                this.button_pause.Enabled = true;
            }
            else
            {
                MessageBox.Show("正在执行操作,稍后");
            }

        }

        private void button_pause_Click(object sender, EventArgs e)
        {
            if(this.backgroundWorker1.IsBusy && 
                this.backgroundWorker1.WorkerSupportsCancellation == true)
            {
                backgroundWorker1.CancelAsync(); //取消下载
            }
        }

        private void bgWorkFileDownLoad_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker bg_worker = sender as BackgroundWorker;
            try 
            {
                HttpWebRequest my_http_web_requset = (HttpWebRequest)WebRequest.Create(textBox1.Text.Trim());
                if(download_size != 0)
                {
                    my_http_web_requset.AddRange(download_size);
                }
                my_web_response = (HttpWebResponse)my_http_web_requset.GetResponse();
                Stream response_stream = my_web_response.GetResponseStream();
                int read_size = 0;
                while(true)
                {
                    if(bg_worker.CancellationPending == true)
                    {
                        e.Cancel = true;
                        break;
                    }
                    read_size = response_stream.Read(buffer_read, 0, buffer_read.Length);
                    if(read_size >0)
                    {
                        download_size += read_size;
                        int precent_complete = (int)((float)download_size / (float)total_size * 100);
                        file_stream.Write(buffer_read, 0, read_size);
                        bg_worker.ReportProgress(precent_complete);
                    }
                    else
                    {
                        break;
                    }
                }

            }
            catch
            {
                throw;
            }
        }

        private void bgWorkFileDownLoad_ProgressChange(object sender, ProgressChangedEventArgs e)
        {
            this.progressBar1.Value = e.ProgressPercentage;
        }
        private void bgWorkerFileDownLoad_RunComlete(object sender, RunWorkerCompletedEventArgs e)
        {
            if(e.Error != null)
            {
                MessageBox.Show(e.Error.Message);
                my_web_response.Close();
            }
            else if(e.Cancelled)
            {
                MessageBox.Show(string.Format("下载暂停,下载文件的地址为{0}\n 已经下载的字节数为:{1}字节",download_path,download_size));
                my_web_response.Close();
                file_stream.Close();
                this.button_down.Enabled = true;
                this.button_pause.Enabled = false;
            }
            else
            {
                MessageBox.Show(string.Format("下载完成,下载文件的地址为{0}\n 已经下载的字节数为:{1}字节", download_path, total_size));
                my_web_response.Close();
                file_stream.Close();
                this.button_down.Enabled = true;
                this.button_pause.Enabled = false;
            }
        }
    }

不过以上的方式并不推荐使用

5.TAP  基于任务的异步模式 (Task-based Asynchronous Pattern)

还有更厉害的

 public partial class Form1 : Form
    {
        private int download_size = 0;
        public string download_path = null;
        long total_size = 0;
        FileStream file_stream = null;



        CancellationTokenSource cts = null;
        Task task = null;
        SynchronizationContext sc;

        public Form1()
        {
            InitializeComponent();
            textBox1.Text = "https://download.microsoft.com/download/2/0/E/20E90413-712F-438C-988E-FDAA79A8AC3D/dotnetfx35.exe";
            this.button_pause.Enabled = false;
            GetTotalSize();
            download_path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\" + Path.GetFileName(this.textBox1.Text.Trim());

            if (File.Exists(download_path))
            {
                FileInfo file_info = new FileInfo(download_path);
                download_size = (int)file_info.Length;
                progressBar1.Value = (int)((float)download_size / (float)total_size * 100);
            }

        }
        private void GetTotalSize()
        {
            HttpWebRequest my_http_web_request = (HttpWebRequest)WebRequest.Create(textBox1.Text.Trim());
            HttpWebResponse response = (HttpWebResponse)my_http_web_request.GetResponse();
            total_size = response.ContentLength;
            response.Close();
        }
        private void button_down_Click(object sender, EventArgs e)
        {
            file_stream = new FileStream(download_path, FileMode.OpenOrCreate);
            file_stream.Seek(download_size, SeekOrigin.Begin);
            this.button_down.Enabled = false;
            this.button_pause.Enabled = true;
            // 上下文同步

            sc = SynchronizationContext.Current;
            cts = new CancellationTokenSource();
            task = new Task(() => Tap_DoWork(textBox1.Text.Trim(), cts.Token, new Progress<int>(p =>
               {
                   sc.Post(new SendOrPostCallback((result) => progressBar1.Value = (int)result), p);
               })));

            task.Start();



        }

        private void button_pause_Click(object sender, EventArgs e)
        {
            cts.Cancel();
        }

        private void Tap_DoWork(string url, CancellationToken ct, IProgress<int> progess)
        {
            int buffer_size = 2048;
            byte[] buffer_read = new byte[buffer_size];
            HttpWebResponse my_web_response = null;
            HttpWebRequest my_http_web_requset = null;

            try
            {
                my_http_web_requset = (HttpWebRequest)WebRequest.Create(url);
                if (download_size != 0)
                {
                    my_http_web_requset.AddRange(download_size);
                }
                my_web_response = (HttpWebResponse)my_http_web_requset.GetResponse();
                Stream response_stream = my_web_response.GetResponseStream();
                int read_size = 0;
                while (true)
                {
                    if (ct.IsCancellationRequested == true)
                    {
                        MessageBox.Show(string.Format("下载暂停,下载文件的地址为{0}\n 已经下载的字节数为:{1}字节", download_path, download_size));
                        my_web_response.Close();
                        file_stream.Close();
                        sc.Post((state) =>
                            {
                                this.button_down.Enabled = true;
                                this.button_pause.Enabled = false;

                            }, null);

                        break;
                    }
                    read_size = response_stream.Read(buffer_read, 0, buffer_read.Length);
                    if (read_size > 0)
                    {
                        download_size += read_size;
                        int precent_complete = (int)((float)download_size / (float)total_size * 100);
                        file_stream.Write(buffer_read, 0, read_size);

                        progess.Report(precent_complete);
                    }
                    else
                    {
                        MessageBox.Show(string.Format("下载完成,下载文件的地址为{0}\n 已经下载的字节数为:{1}字节", download_path, total_size));

                        sc.Post((state) =>
                        {
                            this.button_down.Enabled = true;
                            this.button_pause.Enabled = false;
                        }, null);

                        my_web_response.Close();
                        file_stream.Close();

                        break;
                    }
                }

            }
            catch (AggregateException ex)
            {
                ex.Handle(e => e is OperationCanceledException);
            }
        }
    }

6.async await

  public partial class Form1 : Form
    {
        private int download_size = 0;
        public string download_path = null;
        long total_size = 0;
        FileStream file_stream = null;

        CancellationTokenSource cts = null;
        Task task = null;

        public Form1()
        {
            InitializeComponent();
            textBox1.Text = "https://download.microsoft.com/download/2/0/E/20E90413-712F-438C-988E-FDAA79A8AC3D/dotnetfx35.exe";
            this.button_pause.Enabled = false;
            GetTotalSize();
            download_path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\" + Path.GetFileName(this.textBox1.Text.Trim());

            if (File.Exists(download_path))
            {
                FileInfo file_info = new FileInfo(download_path);
                download_size = (int)file_info.Length;
                progressBar1.Value = (int)((float)download_size / (float)total_size * 100);
            }

        }
        private void GetTotalSize()
        {
            HttpWebRequest my_http_web_request = (HttpWebRequest)WebRequest.Create(textBox1.Text.Trim());
            HttpWebResponse response = (HttpWebResponse)my_http_web_request.GetResponse();
            total_size = response.ContentLength;
            response.Close();
        }
        private async void  button_down_Click(object sender, EventArgs e)
        {
            file_stream = new FileStream(download_path, FileMode.OpenOrCreate);
            file_stream.Seek(download_size, SeekOrigin.Begin);
            this.button_down.Enabled = false;
            this.button_pause.Enabled = true;
            // 上下文同步

            cts = new CancellationTokenSource();
            await Tap_DoWork(textBox1.Text.Trim(), cts.Token, new Progress<int>(p => progressBar1.Value = p));
          
        }

        private  void button_pause_Click(object sender, EventArgs e)
        {
            cts.Cancel();
        }

        private async Task Tap_DoWork(string url, CancellationToken ct, IProgress<int> progess)
        {
            int buffer_size = 2048;
            byte[] buffer_read = new byte[buffer_size];
            HttpWebResponse my_web_response = null;
            HttpWebRequest my_http_web_requset = null;

            try
            {
                my_http_web_requset = (HttpWebRequest)WebRequest.Create(url);
                if (download_size != 0)
                {
                    my_http_web_requset.AddRange(download_size);
                }
                my_web_response = (HttpWebResponse)my_http_web_requset.GetResponse();
                Stream response_stream = my_web_response.GetResponseStream();
                int read_size = 0;
                while (true)
                {
                    if (ct.IsCancellationRequested == true)
                    {
                        MessageBox.Show(string.Format("下载暂停,下载文件的地址为{0}\n 已经下载的字节数为:{1}字节", download_path, download_size));
                        my_web_response.Close();
                        file_stream.Close();
                  
                        this.button_down.Enabled = true;
                        this.button_pause.Enabled = false;
                        break;
                    }
                    read_size =await response_stream.ReadAsync(buffer_read, 0, buffer_read.Length);
                    if (read_size > 0)
                    {
                        download_size += read_size;
                        int precent_complete = (int)((float)download_size / (float)total_size * 100);
                        await file_stream.WriteAsync(buffer_read, 0, read_size);

                        progess.Report(precent_complete);
                    }
                    else
                    {
                        MessageBox.Show(string.Format("下载完成,下载文件的地址为{0}\n 已经下载的字节数为:{1}字节", download_path, total_size));

                       this.button_down.Enabled = true;
                       this.button_pause.Enabled = false;
                   
                        my_web_response.Close();
                        file_stream.Close();

                        break;
                    }
                }

            }
            catch (AggregateException ex)
            {
                ex.Handle(e => e is OperationCanceledException);
            }
        }
    }

所有的一切都封装在async和 await 关键字中

在方法的头部多了 async关键字在具体的方法处增加 awit关键字。

也不存在获取上下问同步对象的代码 async 和 await关键字不会让调用的

方法运行在新的线程中,而是将方法分割成多个片段(片段的界限出现在方法内使用

await的关键字出)并使其中一些片段可以异步运行。await关键字出的代码片段是在线程上

运行的,而整个帆帆的调用确实同步。这种方式的编程不用考虑跨线程访问ui控件的问题。

而大大降低了异步编程的出错概率。

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值