zoukankan      html  css  js  c++  java
  • 异步编程之EAP

    一、概述

    前面我们了解到了APM编程模式,但APM不支持对异步操作的取消和没有提供对进度报告的功能。

    对于界面程序来说,进度报告和取消操作的支持也是必不可少的,为了支持这些功能,微软在.NET 2.0的时候提出了一个新的异步编程模型---基于事件的异步编程模型——EAP。

    实现了基于事件的异步模式的类将具有一个或者多个以Async为后缀的方法和对应的Completed事件,并且这些类都支持异步方法的取消、进度报告。 

    然而在.NET类库中并不是所有的类都支持EAP的,可能有朋友会误认为是不是支持APM的类都支持EAP的呢?在.NET 类库中只有部分的类支持EAP的(并且也只有部分类支持APM),这些类有(共17个类): 

    System.Object的派生类型:

      System.Activies.WorkflowInvoke  

      System.Deployment.Application.ApplicationDeployment

      System.Deployment.Application.InPlaceHosingManager

      System.Net.Mail.SmtpClient

      System.Net.PeerToPeer.PeerNameResolver

      System.Net.PeerToPeer.Collaboration.ContactManager

      System.Net.PeerToPeer.Collaboration.Peer

      System.Net.PeerToPeer.Collaboration.PeerContact

      System.Net.PeerToPeer.Collaboration.PeerNearMe

      System.ServiceModel.Activities.WorkflowControlClient

      System.ServiceModel.Discovery.AnnoucementClient

      System.ServiceModel.Discovery.DiscoveryClient

    System.ComponentModel.Component的派生类型:

    System.ComponentModel.BackgroundWorker

    System.Media.SoundPlay

    System.Net.WebClient

    System.Net.NetworkInformation.Ping

    System.Windows.Forms.PictureBox(继承于Control类,Control类派生于Component类)

    当我们调用实现基于事件的异步模式的类的 XxxAsync方法时,即代表开始了一个异步操作,该方法调用完之后会使一个线程池线程去执行耗时的操作。

    二、Demo

    下面以BackgroundWorker类制作一个下载文件的demo。

    BackgroundWorker类关键点

    调用函数RunWorkerAsync时,会触发DoWork事件;

    调用函数ReportProgress时,会触发ProgressChanged事件;

    当后台操作已完成、被取消或引发异常时发生时,会触发RunWorkerCompleted事件。

      1 using System;
      2 using System.ComponentModel;
      3 using System.IO;
      4 using System.Net;
      5 using System.Threading;
      6 using System.Windows;
      7 
      8 namespace Wpf_EAP
      9 {
     10     public class RequestState
     11     {
     12         private HttpWebRequest request;
     13         public HttpWebRequest Request
     14         {
     15             get
     16             {
     17                 return request;
     18             }
     19             set
     20             {
     21                 request = value;
     22             }
     23         }
     24         private HttpWebResponse response;
     25         public HttpWebResponse Response
     26         {
     27             get
     28             {
     29                 return response;
     30             }
     31             set
     32             {
     33                 response = value;
     34             }
     35         }
     36         public Stream ResponseStream;
     37         public FileStream Filestream = null;
     38 
     39         public byte[] BufferRead = new byte[1024];
     40         public static int Index = 1;
     41         public RequestState(string fileSavePath)
     42         {
     43             //string fileName = "Pic" + (Index++).ToString();
     44             string fileName = "Pic";
     45             string saveFilePath = fileSavePath + fileName + ".jpg";//以下载jpg图片为例
     46             //if(File.Exists(saveFilePath))
     47             //{
     48             //    File.Delete(saveFilePath);
     49             //}
     50             Filestream = new FileStream(saveFilePath, FileMode.OpenOrCreate);
     51         }
     52     }
     53     /// <summary>
     54     /// Interaction logic for MainWindow.xaml
     55     /// </summary>
     56     public partial class MainWindow : Window
     57     {
     58         private string downLoadUrl = @"https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=2298824648,1812234339&fm=200&gp=0.jpg";
     59         public string DownLoadUrl
     60         {
     61             get { return downLoadUrl; }
     62             set { downLoadUrl = value; }
     63         }
     64         private string fileSavePath = @"D:360Downloads";
     65         public string FileSavePath
     66         {
     67             get { return fileSavePath; }
     68             set { fileSavePath = value; }
     69         }
     70         private int downLoadSize = 0;
     71         private BackgroundWorker bgWorker;
     72         private RequestState requestState;
     73         private long totalSize = 0;
     74         public MainWindow()
     75         {
     76             InitializeComponent();
     77             this.DataContext = this;
     78             bgWorker = new BackgroundWorker();
     79             bgWorker.WorkerSupportsCancellation = true;
     80             bgWorker.WorkerReportsProgress = true;
     81             bgWorker.DoWork += bgWorkerFileDownload_DoWork;
     82             bgWorker.ProgressChanged += bgWorkerFileDownload_ProgressChanged;
     83             bgWorker.RunWorkerCompleted += bgWorkerFileDownload_RunWorkerCompleted;
     84 
     85         }
     86         private void GetTotalSize()
     87         {
     88             HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create(DownLoadUrl);
     89             HttpWebResponse response = (HttpWebResponse)myHttpWebRequest.GetResponse();
     90             totalSize = response.ContentLength;
     91             response.Close();
     92         }
     93         private void bgWorkerFileDownload_DoWork(object sender, DoWorkEventArgs e)
     94         {
     95             BackgroundWorker bgworker = sender as BackgroundWorker;
     96             try
     97             {
     98                 GetTotalSize();
     99                 // Do the DownLoad operation
    100                 // Initialize an HttpWebRequest object
    101                 HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create(DownLoadUrl);
    102 
    103                 // If the part of the file have been downloaded, 
    104                 // The server should start sending data from the DownloadSize to the end of the data in the HTTP entity.
    105                 if (downLoadSize != 0)
    106                 {
    107                     myHttpWebRequest.AddRange(downLoadSize);
    108                 }
    109 
    110                 // assign HttpWebRequest instance to its request field.
    111                 requestState.Request = myHttpWebRequest;
    112                 requestState.Response = (HttpWebResponse)myHttpWebRequest.GetResponse();
    113                 requestState.ResponseStream = requestState.Response.GetResponseStream();
    114                 int readSize = 0;
    115                 while (true)
    116                 {
    117                     if (bgworker.CancellationPending == true)
    118                     {
    119                         e.Cancel = true;
    120                         break;
    121                     }
    122 
    123                     readSize = requestState.ResponseStream.Read(requestState.BufferRead, 0, requestState.BufferRead.Length);
    124                     if (readSize > 0)
    125                     {
    126                         downLoadSize += readSize;
    127                         int percentComplete = (int)((float)downLoadSize / (float)totalSize * 100);
    128                         requestState.Filestream.Write(requestState.BufferRead, 0, readSize);
    129                         Thread.Sleep(100);
    130                         // 报告进度,引发ProgressChanged事件的发生
    131                         bgworker.ReportProgress(percentComplete);
    132                     }
    133                     else
    134                     {
    135                         break;
    136                     }
    137                 }
    138             }
    139             catch(Exception err)
    140             {
    141                 MessageBox.Show(err.Message);
    142             }
    143         }
    144         private void bgWorkerFileDownload_ProgressChanged(object sender, ProgressChangedEventArgs e)
    145         {
    146             //progressBar.Value = e.ProgressPercentage;
    147              Dispatcher.BeginInvoke(new Action( ()=> { progressBar.Value = e.ProgressPercentage; } ));
    148         }
    149         private void bgWorkerFileDownload_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    150         {
    151             if (e.Error != null)
    152             {
    153                 MessageBox.Show(e.Error.Message);
    154                 requestState.Response.Close();
    155             }
    156             else if (e.Cancelled)
    157             {
    158                 int percentComplete = (int)((float)downLoadSize / (float)totalSize * 100);
    159                 MessageBox.Show(String.Format("下载暂停,下载的文件地址为:{0}
     已经下载的字节数/总字节: {1}字节/{2}  百分比:{3} %", DownLoadUrl, downLoadSize, totalSize,percentComplete));
    160                 requestState.Response.Close();
    161                 requestState.Filestream.Close();
    162 
    163                 this.btnDownLoad.IsEnabled = true;
    164                 this.btnPause.IsEnabled = false;
    165             }
    166             else
    167             {
    168                 MessageBox.Show(String.Format("下载已完成,下载的文件地址为:{0},文件的总字节数为: {1}字节", DownLoadUrl, totalSize));
    169                 downLoadSize = 0;
    170                 Dispatcher.BeginInvoke(new Action(() => { progressBar.Value = 0; }));
    171                 this.btnDownLoad.IsEnabled = true;
    172                 this.btnPause.IsEnabled = false;
    173                 requestState.Response.Close();
    174                 requestState.Filestream.Close();
    175             }
    176        
    177         }
    178 
    179         private void btnPause_Click(object sender, RoutedEventArgs e)
    180         {
    181             if (bgWorker.IsBusy && bgWorker.WorkerSupportsCancellation == true)
    182             {
    183                 // Pause the asynchronous operation
    184                 // Fire RunWorkerCompleted event
    185                 bgWorker.CancelAsync();
    186             }
    187         }
    188 
    189         private void btnDownLoad_Click(object sender, RoutedEventArgs e)
    190         {
    191             if (bgWorker.IsBusy != true)
    192             {
    193                 bgWorker.RunWorkerAsync();//触发DoWork事件
    194                 // Create an instance of the RequestState 
    195                 requestState = new RequestState(FileSavePath);
    196                 requestState.Filestream.Seek(downLoadSize, SeekOrigin.Begin);
    197                 this.btnDownLoad.IsEnabled = false;
    198                 this.btnPause.IsEnabled = true;
    199             }
    200             else
    201             {
    202                 MessageBox.Show("下载进行中,请稍后...");
    203             }
    204         }
    205     }
    206 }
    View Code
    <Window x:Class="Wpf_EAP.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:Wpf_EAP"
            mc:Ignorable="d"
            Title="MainWindow" Height="350" Width="525">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="50"/>
                <RowDefinition Height="50"/>
                <RowDefinition Height="*"/>
                <RowDefinition Height="*"/>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="100"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="100"/>
            </Grid.ColumnDefinitions>
            <Label Content="DownLoadUrl:" FontSize="14" VerticalAlignment="Center" HorizontalAlignment="Right"></Label>
            <Label Content="FileSavePath:" FontSize="14"  Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Right"></Label>
            <TextBox FontSize="20" BorderBrush="Green" BorderThickness="1"  Grid.Column="1" Margin="5" Grid.Row="1" Text="{Binding FileSavePath}" Name="tbSavePath"/>
            <TextBox Text="{Binding DownLoadUrl}"  FontSize="20" BorderBrush="Green" BorderThickness="1" Name="lbUrl" Grid.Column="1" Margin="5"/>
            <Button Content="DownLoad" Grid.Column="2" Grid.Row="0" FontSize="20" Name="btnDownLoad" VerticalAlignment="Center" Click="btnDownLoad_Click"/>
            <Button Content="Pause" Grid.Column="2" Grid.Row="1" FontSize="20" Name="btnPause" VerticalAlignment="Center" Click="btnPause_Click"/>
            <ProgressBar Grid.Row="2" Grid.ColumnSpan="3" Height="30" Name="progressBar" Minimum="0" Maximum="100"></ProgressBar>
        </Grid>
    </Window>
    View Code


    注:本文参考https://www.cnblogs.com/zhili/archive/2013/05/11/EAP.html

  • 相关阅读:
    P3 创建项目(下)
    P2 创建项目(中)
    P1 创建项目(上)
    ASP.NET Core 3.x 入门视频(完结)
    网易云微专业《职场人必学的Python技能课》
    01.Python配置与运行
    阶段一-03.地址,订单,支付,定时任务开发-第1章 收货地址功能开发-1-6 收货地址
    ASYNC PROGRAMING IN JAVASCRIPT[转]
    Bluebird-NodeJs的Promise
    理解Nodejs的Event Loop
  • 原文地址:https://www.cnblogs.com/3xiaolonglong/p/10375259.html
Copyright © 2011-2022 走看看