欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

.NET4.0版本中基于任務的異步模式(TAP)

 更新時間:2022年06月09日 09:58:54   作者:springsnow  
這篇文章介紹了.NET4.0版本中基于任務的異步模式(TAP),文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下

一、引言

當使用APM的時候,首先我們要先定義用來包裝回調(diào)方法的委托,這樣難免有點繁瑣, 然而使用EAP的時候,我們又需要實現(xiàn)Completed事件和Progress事件,上面兩種實現(xiàn)方式感覺都有點繁瑣。

同時微軟也意識到了這點,所以在.NET 4.0中提出了一個新的異步模式——基于任務的異步模式TAP(Task-based Asynchronous Pattern )。

基于任務的異步模式 (TAP) 是基于 System.Threading.Tasks.Task 命名空間中的 System.Threading.Tasks.Task 和 System.Threading.Tasks類型,這些類型用于表示任意異步操作。是用于新開發(fā)的建議的異步設計模式。

二、什么是TAP——基于任務的異步模式介紹

當看到類中存在TaskAsync為后綴的方法時就代表該類實現(xiàn)了TAP并且基于任務的異步模式同樣也支持異步操作的取消和進度的報告的功能。

在TAP實現(xiàn)中,我們只需要通過向異步方法傳入CancellationToken 參數(shù),因為在異步方法內(nèi)部會對這個參數(shù)的IsCancellationRequested屬性進行監(jiān)控,當異步方法收到一個取消請求時,異步方法將會退出執(zhí)行。

在TAP中,我們可以通過IProgress接口來實現(xiàn)進度報告的功能。

1、計算密集型任務

例如,請考慮使用呈現(xiàn)圖像的異步方法。

任務的主體可以輪詢?nèi)∠麡擞?,如果在呈現(xiàn)過程中收到取消請求,代碼可提前退出。 此外,如果啟動之前收到取消請求,你需要阻止操作:

internal Task RenderAsync(ImageData data, CancellationToken cancellationToken)
{
    return Task.Run(() =>
    {
        var bmp = new Bitmap(data.Width, data.Height);
        for(int y=0; y)
        {
            cancellationToken.ThrowIfCancellationRequested();
            for(int x=0; x)
            {
                // render pixel [x,y] into bmp
            }
        }
        return bmp;
    }, cancellationToken);
}

2、I/O 密集型任務:

假設你想創(chuàng)建一個將在指定時間段后完成的任務。 例如,你可能想延遲用戶界面中的活動。

System.Threading.Timer 類已提供在指定時間段后以異步方式調(diào)用委托的能力,并且你可以通過使用 TaskCompletionSource 將 Task 前端放在計時器上,例如:

public static Task Delay(int millisecondsTimeout)
   {
       TaskCompletionSource tcs = null;
       Timer timer = null;

       timer = new Timer(delegate
       {
           timer.Dispose();
           tcs.TrySetResult(DateTimeOffset.UtcNow);
       }, null, Timeout.Infinite, Timeout.Infinite);

       tcs = new TaskCompletionSource(timer);
       timer.Change(millisecondsTimeout, Timeout.Infinite);
       return tcs.Task;
   }

從 .NET Framework 4.5 開始,Task.Delay 方法正是為此而提供的,并且你可以在另一個異步方法內(nèi)使用它。例如,若要實現(xiàn)異步輪詢循環(huán):

public static async Task Poll(Uri url, CancellationToken cancellationToken,  IProgress<bool> progress)
{
    while(true)
    {
        await Task.Delay(TimeSpan.FromSeconds(10), cancellationToken);
        bool success = false;
        try
        {
            await DownloadStringAsync(url);
            success = true;
        }
        catch { /* ignore errors */ }
        progress.Report(success);
    }
}

三、如何使用TAP——使用基于任務的異步模式來異步編程

下面就讓我們實現(xiàn)自己的異步方法(亮點為只需要一個方法就可以完成進度報告和異步操作取消的功能)

// Download File CancellationToken 參數(shù)賦值獲得一個取消請求 progress參數(shù)負責進度報告
private void DownLoadFile(string url, CancellationToken ct, IProgress<int> progress)
{
    HttpWebRequest request = null;
    HttpWebResponse response = null;
    Stream responseStream = null;
    int bufferSize = 2048;
    byte[] bufferBytes = new byte[bufferSize];
    try
    {
        request = (HttpWebRequest)WebRequest.Create(url);
        if (DownloadSize != 0)
        {
            request.AddRange(DownloadSize);
        }

        response = (HttpWebResponse)request.GetResponse();
        responseStream = response.GetResponseStream();
        int readSize = 0;
        while (true)
        {
            // 收到取消請求則退出異步操作
            if (ct.IsCancellationRequested == true)
            {
                MessageBox.Show(String.Format("下載暫停,下載的文件地址為:{0}\n 已經(jīng)下載的字節(jié)數(shù)為: {1}字節(jié)", downloadPath, DownloadSize));

                response.Close();
                filestream.Close();
                sc.Post((state) =>
                {
                    this.btnStart.Enabled = true;
                    this.btnPause.Enabled = false;
                }, null);

                // 退出異步操作
                break;
            }

            readSize = responseStream.Read(bufferBytes, 0, bufferBytes.Length);
            if (readSize > 0)
            {
                DownloadSize += readSize;
                int percentComplete = (int)((float)DownloadSize / (float)totalSize * 100);
                filestream.Write(bufferBytes, 0, readSize);

                // 報告進度
                progress.Report(percentComplete);
            }
            else
            {
                MessageBox.Show(String.Format("下載已完成,下載的文件地址為:{0},文件的總字節(jié)數(shù)為: {1}字節(jié)", downloadPath, totalSize));

                sc.Post((state) =>
                {
                    this.btnStart.Enabled = false;
                    this.btnPause.Enabled = false;
                }, null);

                response.Close();
                filestream.Close();
                break;
            }
        }
    }
    catch (AggregateException ex)
    {
        // 因為調(diào)用Cancel方法會拋出OperationCanceledException異常 將任何OperationCanceledException對象都視為以處理
        ex.Handle(e => e is OperationCanceledException);
    }
}

這樣只需要上面的一個方法,我們就可以完成上一專題中文件下載的程序,我們只需要在下載按鈕的事件處理程序調(diào)用該方法和在暫停按鈕的事件處理程序調(diào)用CancellationTokenSource.Cancel方法即可,具體代碼為:

#region 字段

private int DownloadSize = 0;
private string downloadPath = null;
private long totalSize = 0;
private FileStream filestream;

private CancellationTokenSource cts = null;
private Task task = null;

private SynchronizationContext sc;

#endregion 字段

#region 構(gòu)造函數(shù)

public FileDownLoadForm()
{
    InitializeComponent();
    string url = "http://download.microsoft.com/download/7/0/3/703455ee-a747-4cc8-bd3e-98a615c3aedb/dotNetFx35setup.exe";
    txbUrl.Text = url;
    this.btnPause.Enabled = false;

    // Get Total Size of the download file
    GetTotalSize();
    downloadPath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\" + Path.GetFileName(this.txbUrl.Text.Trim());
    if (File.Exists(downloadPath))
    {
        FileInfo fileInfo = new FileInfo(downloadPath);
        DownloadSize = (int)fileInfo.Length;
        if (DownloadSize == totalSize)
        {
            string message = "There is already a file with the same name, do you want to delete it? If not, please change the local path. ";
            var result = MessageBox.Show(message, "File name conflict: " + downloadPath, MessageBoxButtons.OKCancel);

            if (result == System.Windows.Forms.DialogResult.OK)
            {
                File.Delete(downloadPath);
            }
            else
            {
                progressBar1.Value = (int)((float)DownloadSize / (float)totalSize * 100);
                this.btnStart.Enabled = false;
                this.btnPause.Enabled = false;
            }
        }
    }
}

#endregion 構(gòu)造函數(shù)

#region 方法

// Start DownLoad File
private void btnStart_Click(object sender, EventArgs e)
{
    filestream = new FileStream(downloadPath, FileMode.OpenOrCreate);
    this.btnStart.Enabled = false;
    this.btnPause.Enabled = true;

    filestream.Seek(DownloadSize, SeekOrigin.Begin);

    // 捕捉調(diào)用線程的同步上下文派生對象
    sc = SynchronizationContext.Current;

    cts = new CancellationTokenSource();
    // 使用指定的操作初始化新的 Task。
    task = new Task(() => Actionmethod(cts.Token), cts.Token);

    // 啟動 Task,并將它安排到當前的 TaskScheduler 中執(zhí)行。
    task.Start();

    //await DownLoadFileAsync(txbUrl.Text.Trim(), cts.Token,new Progress(p => progressBar1.Value = p));
}

// 任務中執(zhí)行的方法
private void Actionmethod(CancellationToken ct)
{
    // 使用同步上文文的Post方法把更新UI的方法讓主線程執(zhí)行
    DownLoadFile(txbUrl.Text.Trim(), ct, new Progress<int>(p =>
        {
            sc.Post(new SendOrPostCallback((result) => progressBar1.Value = (int)result), p);
        }));
}

// Pause Download
private void btnPause_Click(object sender, EventArgs e)
{
    // 發(fā)出一個取消請求
    cts.Cancel();
}

// Get Total Size of File
private void GetTotalSize()
{
    HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create(txbUrl.Text.Trim());
    HttpWebResponse response = (HttpWebResponse)myHttpWebRequest.GetResponse();
    totalSize = response.ContentLength;
    response.Close();
}

四、與其他異步模式和類型互操作

1、從 APM 到 TAP

可以使用 TaskFactory.FromAsync 方法來實現(xiàn)此操作的 TAP 包裝,如下所示:

public static Task<int> ReadAsync(this Stream stream,  byte[] buffer, int offset,  int count)
{
    if (stream == null) 
       throw new ArgumentNullException("stream");
    
    return Task<int>.Factory.FromAsync(stream.BeginRead,  stream.EndRead, buffer,   offset, count, null);
}

此實現(xiàn)類似于以下內(nèi)容: 

 public static Task<int> ReadAsync(this Stream stream,  byte [] buffer, int offset,   int count)
 {
    if (stream == null) 
        throw new ArgumentNullException("stream");

    var tcs = new TaskCompletionSource<int>();

    stream.BeginRead(buffer, offset, count, iar =>
                     {
                        try { 
                           tcs.TrySetResult(stream.EndRead(iar)); 
                        }
                        catch(OperationCanceledException) { 
                           tcs.TrySetCanceled(); 
                        }
                        catch(Exception exc) { 
                           tcs.TrySetException(exc); 
                        }
                     }, null);
    return tcs.Task;
}

2、從EAP到 TAP

public static Task<string> DownloadStringAsync(Uri url)
 {
     var tcs = new TaskCompletionSource<string>();

     var wc = new WebClient();

     wc.DownloadStringCompleted += (s,e) =>
         {
             if (e.Error != null) 
                tcs.TrySetException(e.Error);
             else if (e.Cancelled) 
                tcs.TrySetCanceled();
             else 
                tcs.TrySetResult(e.Result);
         };
     wc.DownloadStringAsync(url);
     return tcs.Task;
}

到此這篇關(guān)于.NET4.0異步模式(TAP)的文章就介紹到這了。希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • ASP.NET?Core托管模型CreateDefaultBuilder()方法

    ASP.NET?Core托管模型CreateDefaultBuilder()方法

    這篇文章介紹了ASP.NET?Core托管模型CreateDefaultBuilder()方法,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-02-02
  • ASP.NET?Core中間件用法與官方常用中間件介紹

    ASP.NET?Core中間件用法與官方常用中間件介紹

    這篇文章介紹了ASP.NET?Core中間件用法與官方常用中間件,文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-03-03
  • C#命名空間System.ComponentModel屬性方法匯總

    C#命名空間System.ComponentModel屬性方法匯總

    本文詳細講解了C#命名空間System.ComponentModel屬性方法,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-01-01
  • asp.net c# 抓取頁面信息方法介紹

    asp.net c# 抓取頁面信息方法介紹

    我們知道,一般網(wǎng)頁中的信息是不斷翻新的,這也要求我們定期的去抓這些新信息,但是這個“定期”該怎么理解,也就是多長時間需要 抓一次該頁面,其實這個定期也就是頁面緩存時間,在頁面的緩存時間內(nèi)我們再次抓取該網(wǎng)頁是沒有必要的,反而給人家服務器造成壓力
    2012-11-11
  • ASP.Net Core MVC基礎系列之服務注冊和管道

    ASP.Net Core MVC基礎系列之服務注冊和管道

    這篇文章介紹了ASP.Net Core MVC中的服務注冊和管道,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-02-02
  • .NET正則表達式的最佳用法

    .NET正則表達式的最佳用法

    本文詳細講解了.NET正則表達式最佳用法,文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-01-01
  • ASP.NET?Core開發(fā)環(huán)境安裝配置

    ASP.NET?Core開發(fā)環(huán)境安裝配置

    這篇文章介紹了ASP.NET?Core開發(fā)環(huán)境安裝配置,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-02-02
  • ASP.NET中HiddenField隱藏域控件的使用方法

    ASP.NET中HiddenField隱藏域控件的使用方法

    本文主要介紹ASP.NET中HiddenField控件的基礎使用方法、事件以及配合javascript的一些使用,希望能幫到大家。
    2016-04-04
  • ASP.NET?Core命名空間System.Text.Encodings.Web介紹

    ASP.NET?Core命名空間System.Text.Encodings.Web介紹

    這篇文章介紹了ASP.NET?Core命名空間System.Text.Encodings.Web,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-01-01
  • .Net創(chuàng)建型設計模式之原型模式(Prototype)

    .Net創(chuàng)建型設計模式之原型模式(Prototype)

    這篇文章介紹了.Net設計模式之原型模式(Prototype),文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-05-05

最新評論