重新想象 Windows 8 Store Apps (44) - 多線程之異步編程: 經典和最新的異步編程模型, IAsyncInfo 與 Task 相互轉換


[源碼下載]


重新想象 Windows 8 Store Apps (44) - 多線程之異步編程: 經典和最新的異步編程模型, IAsyncInfo 與 Task 相互轉換



作者:webabcd


介紹
重新想象 Windows 8 Store Apps 之 異步編程

  • 經典的異步編程模型(IAsyncResult)
  • 最新的異步編程模型(async 和 await)
  • 將 IAsyncInfo 轉換成 Task
  • 將 Task 轉換成 IAsyncInfo



示例
1、使用經典的異步編程模型(IAsyncResult)實現一個支持異步操作的類
Thread/Async/ClassicAsync.cs

/*
 * 使用經典的異步編程模型(IAsyncResult)實現一個支持異步操作的類
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace XamlDemo.Thread.Async
{
    public class ClassicAsync
    {
        private delegate string HelloDelegate(string name);

        private HelloDelegate _helloDelegate;

        public ClassicAsync()
        {
            _helloDelegate = new HelloDelegate(Hello);
        }

        private string Hello(string name)
        {
            new ManualResetEvent(false).WaitOne(3000);
            return "hello: " + name;
        }

        // begin 方法
        public IAsyncResult BeginRun(string name, AsyncCallback callback, Object state)
        {
            // 新開線程,去執行 Hello() 方法,callback 是回調,state 是上下文
            return _helloDelegate.BeginInvoke(name, callback, state);
        }

        // end 方法
        public string EndRun(IAsyncResult ar)
        {
            if (ar == null)
                throw new NullReferenceException("IAsyncResult 不能為 null");

            return _helloDelegate.EndInvoke(ar);
        }
    }
}

Thread/Async/ClassicAsyncDemo.xaml

<Page
    x:Class="XamlDemo.Thread.Async.ClassicAsyncDemo"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:XamlDemo.Thread.Async"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid Background="Transparent">
        <StackPanel Margin="120 0 0 0">

            <TextBlock Name="lblMsg" FontSize="14.667" />

            <Button Name="btnIAsyncResult" Content="IAsyncResult 的 Demo" Click="btnIAsyncResult_Click_1" Margin="0 10 0 0" />

        </StackPanel>
    </Grid>
</Page>

Thread/Async/ClassicAsyncDemo.xaml.cs

/*
 * 演示如何通過經典的異步編程模型(IAsyncResult)來進行異步操作
 * 
 * IAsyncResult - 異步操作結果
 *     AsyncState - 上下文
 *     IsCompleted - 異步操作是否已完成
 *     AsyncWaitHandle -  獲取用於等待異步操作完成的 System.Threading.WaitHandle 對象(通過 WaitHandle.WaitOne() 在當前線程等待)
 */

using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace XamlDemo.Thread.Async
{
    public sealed partial class ClassicAsyncDemo : Page
    {
        System.Threading.SynchronizationContext _syncContext;

        public ClassicAsyncDemo()
        {
            this.InitializeComponent();

            // 獲取當前 UI 線程
            _syncContext = System.Threading.SynchronizationContext.Current;
        }

        private void btnIAsyncResult_Click_1(object sender, RoutedEventArgs e)
        {
            ClassicAsync classicAsync = new ClassicAsync();

            IAsyncResult ar = classicAsync.BeginRun("webabcd", new AsyncCallback(Callback), classicAsync);

            lblMsg.Text = "開始執行,3 秒后完成";
        }

        private void Callback(IAsyncResult ar)
        {
            ClassicAsync classicAsync = (ClassicAsync)ar.AsyncState;
            string result = classicAsync.EndRun(ar);

            _syncContext.Post(
                (ctx) =>
                {
                    lblMsg.Text = result;
                },
                null);
        }
    }
}


2、演示如何通過最新的異步編程模型(async 和 await)來進行異步操作
Thread/Async/NewAsyncDemo.xaml

<Page
    x:Class="XamlDemo.Thread.Async.NewAsyncDemo"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:XamlDemo.Thread.Async"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid Background="Transparent">
        <StackPanel Margin="120 0 0 0">

            <TextBlock Name="lblMsg" FontSize="14.667" />

            <Button Name="btnTaskWithoutReturn" Content="執行一個不帶返回值的 Task" Click="btnTaskWithoutReturn_Click_1" Margin="0 10 0 0" />

            <Button Name="btnTaskWithReturn" Content="執行一個帶返回值的 Task" Click="btnTaskWithReturn_Click_1" Margin="0 10 0 0" />

            <Button Name="btnMultiTask" Content="並行執行多個 Task" Click="btnMultiTask_Click_1" Margin="0 10 0 0" />

            <Button Name="btnTaskWithoutAwait" Content="執行一個不 await 的 Task" Click="btnTaskWithoutAwait_Click_1" Margin="0 10 0 0" />

        </StackPanel>
    </Grid>
</Page>

Thread/Async/NewAsyncDemo.xaml.cs

/*
 * 演示如何通過最新的異步編程模型(async 和 await)來進行異步操作
 * 
 * 注:
 * 1、要想 await,其所在方法必須標記為 async
 * 2、方法被標記為 async 是為了讓編譯器重新編寫該方法,使 await 中的內容重新編寫為具有 GetAwaiter() 等實際異步邏輯的代碼
 */

using System;
using System.Threading;
using System.Threading.Tasks;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace XamlDemo.Thread.Async
{
    public sealed partial class NewAsyncDemo : Page
    {
        private static int _count = 0;

        public NewAsyncDemo()
        {
            this.InitializeComponent();
        }

        // 不帶返回值的 Task
        private async Task TaskWithoutReturn()
        {
            // 在另一個線程 sleep 1000 毫秒,然后回到 UI 線程
            await Task.Delay(1000);
            // await Task.Delay(Timeout.Infinite); 長眠於此
            // await Task.Delay(Timeout.InfiniteTimeSpan); 長眠於此

            // 直接在當前線程 sleep 可以使用如下方法,因為 WinRT 中沒有 Thread.Sleep() 了
            // new ManualResetEvent(false).WaitOne(1000);

            Interlocked.Increment(ref _count);
        }

        // 帶返回值的 Task
        private async Task<int> TaskWithReturn()
        {
            await Task.Delay(1000);
            Interlocked.Increment(ref _count);

            return _count;
        }

        // 演示不帶返回值的異步操作
        private async void btnTaskWithoutReturn_Click_1(object sender, RoutedEventArgs e)
        {
            // ConfigureAwait(false) - 異步操作后不返回 UI 線程,可節省一點點資源。默認值:ConfigureAwait(true)
            await TaskWithoutReturn().ConfigureAwait(false);
            lblMsg.Text = "count: " + _count.ToString();
        }

        // 演示帶返回值的異步操作
        private async void btnTaskWithReturn_Click_1(object sender, RoutedEventArgs e)
        {
            int result = await TaskWithReturn();
            lblMsg.Text = "count: " + result.ToString();
        }

        // 演示多任務並行執行的異步操作
        private async void btnMultiTask_Click_1(object sender, RoutedEventArgs e)
        {
            Task task = Task.WhenAll(TaskWithoutReturn(), TaskWithoutReturn(), TaskWithoutReturn());

            DateTime dt = DateTime.Now;

            await task;

            lblMsg.Text = "count: " + _count.ToString() + ", 執行時間: " + (DateTime.Now - dt).TotalSeconds.ToString() + "";
        }

        // 演示如何執行一個不 await 的 Task
        private void btnTaskWithoutAwait_Click_1(object sender, RoutedEventArgs e)
        {
            // 讓 task 在新線程執行去吧,本線程不管它是什么執行情況
            Task task = TaskWithoutReturn();
            lblMsg.Text = "count: " + _count.ToString();
        }
    }
}


3、演示如何將 IAsyncInfo(IAsyncAction, IAsyncOperation, IAsyncActionWithProgress, IAsyncOperationWithProgress) 轉成 Task
Thread/Async/IAsyncInfo2Task.xaml

<Page
    x:Class="XamlDemo.Thread.Async.IAsyncInfo2Task"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:XamlDemo.Thread.Async"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid Background="Transparent">
        <StackPanel Margin="120 0 0 0">

            <TextBlock Name="lblMsg" FontSize="14.667" />

        </StackPanel>
    </Grid>
</Page>

Thread/Async/IAsyncInfo2Task.xaml.cs

/*
 * 演示如何將 IAsyncInfo(IAsyncAction, IAsyncOperation, IAsyncActionWithProgress, IAsyncOperationWithProgress) 轉成 Task
 */

using System;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;

namespace XamlDemo.Thread.Async
{
    public sealed partial class IAsyncInfo2Task : Page
    {
        public IAsyncInfo2Task()
        {
            this.InitializeComponent();
        }

        protected async override void OnNavigatedTo(NavigationEventArgs e)
        {
            // 用於取消 Task
            CancellationTokenSource cts = new CancellationTokenSource();

            // 創建一個 IAsyncInfo
            IAsyncOperation<int> action = AsyncInfo.Run<int>(
               (token) =>
                   Task.Run<int>(
                       () =>
                       {
                           token.WaitHandle.WaitOne(3000);
                           token.ThrowIfCancellationRequested();

                           return 10 * 10;
                       },
                       token));

            lblMsg.Text = "開始執行,3 秒后完成";

            // 將 IAsyncOperation 轉換成 Task
            // AsTask() 是擴展方法,其邏輯在 System.WindowsRuntimeSystemExtensions 類中
            Task<int> task = action.AsTask<int>(cts.Token);
            int result = await task;

            lblMsg.Text = "結果:" + result.ToString();
        }
    }
}


4、演示如何將 Task 轉成 IAsyncInfo(IAsyncAction, IAsyncOperation)
Thread/Async/Task2IAsyncInfo.xaml

<Page
    x:Class="XamlDemo.Thread.Async.Task2IAsyncInfo"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:XamlDemo.Thread.Async"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid Background="Transparent">
        <StackPanel Margin="120 0 0 0">

            <TextBlock Name="lblMsg" FontSize="14.667" />

        </StackPanel>
    </Grid>
</Page>

Thread/Async/Task2IAsyncInfo.xaml.cs

/*
 * 演示如何將 Task 轉成 IAsyncInfo(IAsyncAction, IAsyncOperation)
 */

using System;
using System.Threading;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;

namespace XamlDemo.Thread.Async
{
    public sealed partial class Task2IAsyncInfo : Page
    {
        public Task2IAsyncInfo()
        {
            this.InitializeComponent();
        }

        protected async override void OnNavigatedTo(NavigationEventArgs e)
        {
            // 用於取消 IAsyncInfo(注意:本例中的 IAsyncInfo 是從 Task 轉換過來的,所以 IAsyncInfo.Cancel() 方法無效)
            CancellationTokenSource cts = new CancellationTokenSource();

            // 創建一個 Task
            Task<int> task = Task.Run<int>(
                () =>
                {
                    cts.Token.WaitHandle.WaitOne(3000);
                    cts.Token.ThrowIfCancellationRequested();

                    return 10 * 10;
                },
                cts.Token);

            lblMsg.Text = "開始執行,3 秒后完成";

            // 將 Task 轉換成 IAsyncOperation
            // AsAsyncAction(), AsAsyncOperation() 是擴展方法,其邏輯在 System.WindowsRuntimeSystemExtensions 類中
            IAsyncOperation<int> operation = task.AsAsyncOperation<int>();
            int result = await operation;

            lblMsg.Text = "結果:" + result.ToString();           
        }
    }
}



OK
[源碼下載]


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM