多线程之异步编程:经典和最新的异步编程模型,async与await

ansen312 ansen312     2022-08-08     131

关键词:

经典的异步编程模型(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();           
        }
    }
}
复制代码

异步编程之eventloop

...背后的原理。我们都知道,Dart语言和Javascript一样都是单线程模型的,而不是像类似Java、C#多线程模型。同时也就意味着Dart不存在像Java多线程线程安全以及锁竞争情况,开发也会比较简单清晰。虽然Dart是单线程模型的,但是我... 查看详情

任务task系列之异步编程(asyncandawait)(代码片段)

...、连接远程计算机或查询数据库=异步操作在主应用程序线程以外的线程中执行。应用程序调用方法异步执行某个操作时,应用程序可在异步方法执行其任务时继续执行。  异步与多线程的关系:我们已经知道,异步和多线程... 查看详情

网络编程之异步io,rabbitmq笔记

对于网络并发编程而言,多线程与多进程算是最常见的需求场景了。毕竟网站开放就是想要更多的流量访问的。回顾回顾下之前学过的关于线程,进程和协程的知识点IO密集型任务--用多线程更好计算密集型任务--用多进程更好&nb... 查看详情

异步编程之事件循环机制(代码片段)

JavaScript是一门单线程语言,我们可以通过异步编程的方式来实现实现类似于多线程语言的并发操作。本文着重讲解通过事件循环机制来实现多个异步操作的有序执行、并发执行;通过事件队列实现同级多个并发操作的先后执行... 查看详情

异步多线程编程模型

...际的处理器,也会产生一个虚拟的处理器,相当于四核八线程。 CPU会缓存未完成的线程,L1,L2,L3级缓存,如果不够用,则会存在内存里。 一个.NET程序运行则会形成 查看详情

python异步编程全攻略(代码片段)

如果你厌倦了多线程,不妨试试python的异步编程,再引入async,await关键字之后语法变得更加简洁和直观,又经过几年的生态发展,现在是一个很不错的并发模型。下面介绍一下python异步编程的方方面面。与多线程的比较因为GIL的... 查看详情

c#(094):异步和多线程的区别

一、区别和联系异步和多线程有什么区别?其实,异步是目的,而多线程是实现这个目的的方法。异步是说,A发起一个操作后(一般都是比较耗时的操作,如果不耗时的操作就没有必要异步了),可以继续自顾自的处理它自己... 查看详情

异步编程和多线程有啥区别?

】异步编程和多线程有啥区别?【英文标题】:Whatisthedifferencebetweenasynchronousprogrammingandmultithreading?异步编程和多线程有什么区别?【发布时间】:2016-04-1308:50:31【问题描述】:我认为它们基本上是一样的——编写在处理器之间... 查看详情

python爬虫编程思想(26):twisted的异步编程模型

       目录1.同步编程模型2.线程编程模型3.异步编程模型         学习Twisted框架之前,先要了解一下异步编程模型。可能很多读者会认为,异步编程就是多线程编程,其... 查看详情

python网络编程04异步与同步编程事件驱动

1、同步模型和异步模型下图展示了,同步单线程、同步多线程以及异步单线程三种模式下程序随着时间的推移所做的工作。这个程序有3个任务需要完成,每个任务都在等待I/O操作时阻塞自身。阻塞在I/O操作上所花费的时间已经... 查看详情

异步编程如何在单线程编程模型中工作?

】异步编程如何在单线程编程模型中工作?【英文标题】:HowdoesAsynchronousprogrammingworkinasinglethreadedprogrammingmodel?【发布时间】:2012-02-1710:38:22【问题描述】:我在浏览node.js的细节时才知道,它支持异步编程,尽管它本质上提供了... 查看详情

java多线程编程之异步(代码片段)

日常开发中我们在一个接口中需要处理多个任务,通常都是串行的,这样导致接口的响应时间是每个任务的执行时间的总和。为了缩短响应时间,通常会使用异步处理多任务。需求举例:查询书籍基本信息,... 查看详情

msdn搬运之[异步编程设计模式]

...、连接远程计算机或查询数据库。异步操作在主应用程序线程以外的线程中执行。应用程序调用方法异步执行某个操作时,应用程序可在异步方法执行其任务时继续执行。.NETFramework为异步操作提供两种设计模式:使用IAsyncResult... 查看详情

并发编程目录

...守护进程1-5互斥锁1-6队列1-7生产者消费者模型并发编程之线程2-1线程理论2-2开启线程的两种方式2-3多线程和多进程的区别2-4Thread对象的其他属性或方法2-5守护线程2-6GIL全局解释器锁2-7死锁现象和递归锁2-8信号量Event定时器2-9线程q... 查看详情

c#的多线程——使用async和await来完成异步编程(asynchronousprogrammingwithasyncandawait)

https://msdn.microsoft.com/zh-cn/library/mt674882.aspx侵删 更新于:2015年6月20日欲获得最新的VisualStudio2017RC文档,参考VisualStudio2017RCDocumentation。使用异步编程,你可以避免性能瓶颈和提升总体相应效率。然而,传统的异步方法代码的编... 查看详情

多线程异步编程示例和实践-thread和threadpool

说到多线程异步编程,总会说起Thread、ThreadPool、Task、TPL这一系列的技术。总结整理了一版编程示例和实践,分享给大家。先从Thread和ThreadPool说起:1.创建并启动线程2.暂停线程当前线程在执行Thread.Sleep方法时,会等待指定的时... 查看详情

异步编程之isolate

...说到了Dart中的EventLoop(事件循环)。我们知道了Dart是单线程模型,也就是实现异步需要借助EventLoop来进行事件驱动。所以Dart只有一个主线程,其实在Dart中并不是叫Thread,而是有个专门名词叫isolate(隔离)。其实在Dart也会遇到... 查看详情

juc并发编程多线程设计模式--异步模式之生产者/消费者(代码片段)

...停中的GuardObject不同,不需要产生结果和消费结果的线程一一对应消费队列可以用来平衡生产和消费的线程资源生产者仅负责产生结果数据,不关心数据该如何处理,而消费者专心处理结果数据消息队列是有容量限制... 查看详情