重新想象 Windows 8 Store Apps (44) - 多线程之异步编程: 经典和最新的异步编程模型, IAsyncInfo 与 Task 相互转换

简介: 原文:重新想象 Windows 8 Store Apps (44) - 多线程之异步编程: 经典和最新的异步编程模型, IAsyncInfo 与 Task 相互转换[源码下载] 重新想象 Windows 8 Store Apps (44) - 多线程之异步编程: 经典和最新的异步编程模型, IA...
原文: 重新想象 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
[源码下载]

目录
相关文章
|
9月前
|
设计模式 缓存 安全
【JUC】(6)带你了解共享模型之 享元和不可变 模型并初步带你了解并发工具 线程池Pool,文章内还有饥饿问题、设计模式之工作线程的解决于实现
JUC专栏第六篇,本文带你了解两个共享模型:享元和不可变 模型,并初步带你了解并发工具 线程池Pool,文章中还有解决饥饿问题、设计模式之工作线程的实现
595 2
|
编解码 网络协议 API
Netty运行原理问题之Netty的主次Reactor多线程模型工作的问题如何解决
Netty运行原理问题之Netty的主次Reactor多线程模型工作的问题如何解决
200 1
|
安全 Java 调度
Netty源码—3.Reactor线程模型二
本文主要介绍了NioEventLoop的执行总体框架、Reactor线程执行一次事件轮询、Reactor线程处理产生IO事件的Channel、Reactor线程处理任务队列之添加任务、Reactor线程处理任务队列之执行任务、NioEventLoop总结。
|
安全 Java
Netty源码—2.Reactor线程模型一
本文主要介绍了关于NioEventLoop的问题整理、理解Reactor线程模型主要分三部分、NioEventLoop的创建和NioEventLoop的启动。
|
缓存 NoSQL 中间件
Redis的线程模型
Redis采用单线程模型确保操作的原子性,每次只执行一个操作,避免并发冲突。它通过MULTI/EXEC事务机制、Lua脚本和复合指令(如MSET、GETSET等)保证多个操作要么全成功,要么全失败,确保数据一致性。Redis事务在EXEC前失败则不执行任何操作,EXEC后失败不影响其他操作。Pipeline虽高效但不具备原子性,适合非热点时段的数据调整。Redis 7引入Function功能,支持函数复用,简化复杂业务逻辑。总结来说,Redis的单线程模型简单高效,适用于高并发场景,但仍需合理选择指令执行方式以发挥其性能优势。
393 6
|
消息中间件 存储 NoSQL
剖析 Redis List 消息队列的三种消费线程模型
Redis 列表(List)是一种简单的字符串列表,它的底层实现是一个双向链表。 生产环境,很多公司都将 Redis 列表应用于轻量级消息队列 。这篇文章,我们聊聊如何使用 List 命令实现消息队列的功能以及剖析消费者线程模型 。
剖析 Redis List 消息队列的三种消费线程模型
|
Java 数据库 Android开发
一个Android App最少有几个线程?实现多线程的方式有哪些?
本文介绍了Android多线程编程的重要性及其实现方法,涵盖了基本概念、常见线程类型(如主线程、工作线程)以及多种多线程实现方式(如`Thread`、`HandlerThread`、`Executors`、Kotlin协程等)。通过合理的多线程管理,可大幅提升应用性能和用户体验。
757 15
一个Android App最少有几个线程?实现多线程的方式有哪些?
|
并行计算 JavaScript 前端开发
单线程模型
【10月更文挑战第15天】
|
开发框架 Java .NET
.net core 非阻塞的异步编程 及 线程调度过程
【11月更文挑战第12天】本文介绍了.NET Core中的非阻塞异步编程,包括其基本概念、实现方式及应用示例。通过`async`和`await`关键字,程序可在等待I/O操作时保持线程不被阻塞,提高性能。文章还详细说明了异步方法的基础示例、线程调度过程、延续任务机制、同步上下文的作用以及如何使用`Task.WhenAll`和`Task.WhenAny`处理多个异步任务的并发执行。
455 1
|
安全 Java
Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧
【10月更文挑战第20天】Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧,包括避免在循环外调用wait()、优先使用notifyAll()、确保线程安全及处理InterruptedException等,帮助读者更好地掌握这些方法的应用。
316 1

热门文章

最新文章