C#中使用 async await TaskCompletionSource<T>实现异步逻辑同步写

Task、async 和 await 是 C# 中用于处理异步编程的关键概念。它们一起构成了异步编程的基础。

Task

Task 是表示异步操作的抽象,它属于 System.Threading.Tasks 命名空间。Task 可以表示已经完成的任务、正在运行的任务或者尚未开始的任务。通过 Task,可以执行异步操作、并发操作,以及异步等待任务完成。

async 和 await

async 和 await 关键字是异步编程的基础构造,用于简化异步代码的编写。它们通常一起使用,使得编写异步代码更加直观、易读。

async

关键字用于定义一个异步方法。异步方法可以包含 await 操作符,并且在异步执行期间可以被挂起,而不会阻塞调用线程。

await

await 操作符用于等待异步操作完成,并返回异步操作的结果。在 async 方法中,await 会将控制权返回给调用者,而不会阻塞线程,从而提高了程序的响应性。

TaskCompletionSource

TaskCompletionSource 是用于创建和控制 Task 实例的一种灵活的方式。通常情况下,Task 表示一个异步操作的结果,而 TaskCompletionSource 则允许你手动控制异步操作的完成。
tcs.SetResult(42) 来设置异步操作的结果
tcs.SetCanceled() 异步取消
tcs.SetException() 异常
TaskCompletionSource 成为一种强大的工具,用于自定义异步操作的实现和控制。

例子 直接上结果

在这里插入图片描述
以往的代码实现上都是请求一个异步操作挂载一个回调方法
使用Task可以轻松实现异步操作同步写代码

public class LoginLogic
{
    public async static void Call()
    {
        C2S_Login c2S_Login = new C2S_Login()
        {
            name = "wukong",
            password = "123456",
        };

        S2C_Login s2C_Login = await TaskLogic.Instance.Call<S2C_Login>(c2S_Login);
        Debug.LogError($"接收消息, id: {s2C_Login.id}, time: {s2C_Login.time}, location: {s2C_Login.location}");
        //这里直接处理后续逻辑
    }
}

public class Test : MonoBehaviour
{
    void Start()
    {
        LoginLogic.Call();
    }
}

代码实现

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Threading.Tasks;
using System;
using System.Threading;

namespace Game
{
    public interface IResponse
    {
        public int id { get; set; }
    }

    public interface IRequest
    {
        public int id { get; set; }
    }

    public class C2S_Login : IRequest
    {
        public int id { get; set; }
        public string name;
        public string password;
    }

    public class S2C_Login : IResponse
    {
        public int id { get; set; }
        public int time;
        public string token;
        public string location;
    }

    public class RPCInfo : IDisposable
    {
        public int id;
        public TaskCompletionSource<IResponse> tcs;
        public CancellationTokenSource cts;

        public void SetResult(IResponse response)
        {
            tcs?.SetResult(response);
        }

        public void Dispose()
        {
            cts?.Dispose();
        }
    }

    public class TaskLogic
    {
        private static TaskLogic _instance;
        private int _id;
        private Dictionary<int, RPCInfo> _rpcs;

        //单位毫秒
        private const int RPC_TIMEOUT = 5000;

        public static TaskLogic Instance
        {
            get
            {
                if (_instance == null)
                    _instance = new TaskLogic();

                return _instance;
            }
        }

        public TaskLogic()
        {
            Init();
        }

        public string GetName()
        {
            return "TaskLogic";
        }

        public bool Init()
        {
            _rpcs = new Dictionary<int, RPCInfo>();
            return true;
        }

        private async void Send(IRequest request)
        {
            await Task.Run(async () =>
            {
                //这段代码只是用于模拟发送
                C2S_Login c2S_Login = request as C2S_Login;
                Debug.LogError($"发送消息, Name: {c2S_Login.name}, password: {c2S_Login.password}");

                //延迟一秒
                await Task.Delay(2000);

                //模拟接收
                S2C_Login s2C_Login = new S2C_Login()
                {
                    id = request.id,
                    time = DateTime.Now.Millisecond,
                    location = "北京",
                };

                Recv(s2C_Login);
            });
        }

        public async Task<T> Call<T>(IRequest request) where T : class, IResponse, new()
        {
            Interlocked.CompareExchange(ref _id, 0, int.MaxValue);
            request.id = Interlocked.Increment(ref _id);
            //1.模拟一下发消息, 延迟1秒后调用回复
            Send(request);
            //2.等待消息返回
            IResponse response = await WaitTask(request);
            return response as T;
        }

        private Task<IResponse> WaitTask(IRequest request)
        {
            TaskCompletionSource<IResponse> tcs = new TaskCompletionSource<IResponse>();
            CancellationTokenSource cts = new CancellationTokenSource();
            cts.CancelAfter(RPC_TIMEOUT);
            cts.Token.Register(() =>
            {
                Debug.LogError($"time out: {request}");
                _rpcs.Remove(request.id);
            });

            RPCInfo rpcInfo = new RPCInfo() { id = request.id, tcs = tcs, cts = cts };
            _rpcs.Add(request.id, rpcInfo);
            return rpcInfo.tcs.Task;
        }

        private void Recv(IResponse response)
        {
            RPCInfo rpcInfo;
            if (!_rpcs.TryGetValue(response.id, out rpcInfo))
                return;

            rpcInfo.Dispose();
            rpcInfo.SetResult(response);
            _rpcs.Remove(response.id);
        }

        public void UnInit()
        {
        }

        public void Update()
        {
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/291755.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

算法导论复习——CHP16 贪心算法

定义 每一步都做出当前看来最优的操作。 问题引入——活动选择问题 问题描述 活动选择问题就是对给定的包含n个活动的集合S&#xff0c;在已知每个活动开始时间和结束时间的条件下&#xff0c;从中选出最多可兼容活动的子集合&#xff0c;称为最大兼容活动集合。 不失一般性&a…

【C++入门】C++内存管理

目录 前言 C/C内存分布 C内存管理方式 1. new和delete操作内置类型 快速了解与使用 2. new和delete操作自定义类型 3. operator new与operator delete 4. operator new [ ] *5.定位new 6. malloc/free和new/delete的区别 总结 前言 C作为一种面向对象的编程语言&#xff…

AI:110-基于深度学习的药物分子结构生成与预测

🚀点击这里跳转到本专栏,可查阅专栏顶置最新的指南宝典~ 🎉🎊🎉 你的技术旅程将在这里启航! 从基础到实践,深入学习。无论你是初学者还是经验丰富的老手,对于本专栏案例和项目实践都有参考学习意义。 ✨✨✨ 每一个案例都附带有在本地跑过的关键代码,详细讲解供…

Unity ab包如何加密

「ab包」全称为 AssetBundle &#xff0c;是Unity提供的一种资源存储压缩包。其中储存了游戏的资源&#xff0c;如图片、模型、纹理、音视频、代码等文件。 由于ab包具有灵活储存、支持热更、包体较小且便于管理等优势&#xff0c;已经成为了市面上主流的游戏资源压缩方式。 …

Jmeter(七) - 从入门到精通 - 建立数据库测试计划实战<MySQL数据库>(详解教程)

1.简介 在实际工作中&#xff0c;我们经常会听到数据库的性能和稳定性等等&#xff0c;这些有时候也需要测试工程师去评估和测试&#xff0c;上一篇文章宏哥主要介绍了jmeter连接和创建数据库测试计划的过程,宏哥在文中通过示例和代码非常详细地介绍给大家&#xff0c;希望对各…

【中小型企业网络实战案例 七】配置限速

相关学习文章&#xff1a; 【中小型企业网络实战案例 一】规划、需求和基本配置 【中小型企业网络实战案例 二】配置网络互连互通【中小型企业网络实战案例 三】配置DHCP动态分配地址 【中小型企业网络实战案例 四】配置OSPF动态路由协议【中小型企业网络实战案例 五】配置可…

51单片机(STC8)-- GPIO输入输出

文章目录 I/O口相关寄存器端口数据寄存器端口模式配置寄存器&#xff08;PxM0&#xff0c;PxM1&#xff09;端口上拉电阻控制寄存器(PxPU)关于I/O的注意事项 配置I/O口I/O设置demoI/O端口模式LED控制&#xff08;I/O输出&#xff09;按键检测&#xff08;I/O输入&#xff09; S…

【模拟量采集1.2】电阻信号采集

【模拟量采集1.2】电阻信号采集 1 怎么测&#xff1f;2 测输入电阻电压即转为测模拟电压值&#xff0c;这里需要考虑选用怎样的辅助电阻&#xff1f;3 实际电路分析3.1 在不考虑 VCC-5V 电压的纹波等情况时&#xff08;理想化此时输入的 VCC 就是稳定的 5V&#xff09;3.2 若考…

拖拽式工作流好用吗?有何特点?

大家都知道&#xff0c;随着行业的进步和发展&#xff0c;低代码技术平台也迎来了蓬勃发展期。很多企业喜欢使用低代码实现提质增效的办公效果&#xff0c;拖拽式工作流是其中一个功能&#xff0c;是助力企业实现流程化办公的得力助手。那么&#xff0c;拖拽式工作流好用吗&…

robots.txt

####什么是robots.txt? ​ robots.txt是一个协议,我们可以把它理解为一个网站的"管家",它会告诉搜索引擎哪些页面可以访问,哪些页面不能访问。也可以规定哪些搜索引擎可以访问我们的网站而哪些搜索引擎不能爬取我们网站的信息等等,是网站管理者指定的"君子协议…

FMQL BOOT.bin固化文件生成及固化流程记录

FMQL BOOT.bin固化文件生成及固化流程记录 一、概述 此篇记录上海复旦微JFMQL15T开发板 烧录固化文件BOOT.bin生成及固化操作流程。 以上一篇文章FQML_AXI_GPIO工程构建调试记录 中的工程为基础&#xff0c;做更改。 二、vivado工程配置 2.1新建工程 打开FQML_AXI_GPIO工程…

Unity | Shader基础知识番外(向量数学知识速成)

目录 一、向量定义 二、计算向量 三、向量的加法&#xff08;连续行走&#xff09; 四、向量的长度 五、单位向量 六、向量的点积 1 计算 2 作用 七、向量的叉乘 1 承上启下 2 叉乘结论 3 叉乘的计算&#xff08;这里看不懂就百度叉乘计算&#xff09; 八、欢迎收…

视频号小店全新赛道,新手如何入驻?

我是电商珠珠 视频号小店为视频号团队所研发。距今为止也才发展了一年时间&#xff0c;在23年下半年掀起了不小的浪花。 我做视频号小店也有一年时间了&#xff0c;在他刚开始三个月的时候&#xff0c;就开始带着团队一起做。到现在也拥有了自己的视频号小店运营团队&#xf…

数模学习day06-主成分分析

主成分分析(Principal Component Analysis,PCA)主成分分析是一种降维算法&#xff0c;它能将多个指标转换为少数几个主成分&#xff0c;这些主成分是原始变量的线性组合&#xff0c;且彼此之间互不相关&#xff0c;其能反映出原始数据的大部分信息。一般来说当研究的问题涉及到…

P5534 【XR-3】等差数列————C++、C

目录 【XR-3】等差数列题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 样例 #2样例输入 #2样例输出 #2 提示 解题思路Code运行结果 【XR-3】等差数列 题目描述 小 X 给了你一个等差数列的前两项以及项数&#xff0c;请你求出这个等差数列各项之和。 等差数列&#…

JavaWeb——后端之Mybatis

四、Mybatis 概念&#xff1a; Mybatis是一款持久层&#xff08;Dao层&#xff09;框架&#xff0c;用于简化JDBC&#xff08;Sun操作数据库的规范&#xff0c;较繁琐&#xff09;的开发 历史&#xff1a; Apache的一个开源项目iBatis&#xff0c;2010年由apache迁移到了goog…

Spring见解

1.Spring概述 1.1.Spring介绍 Spring是轻量级Java EE应用开源框架&#xff08;官网&#xff1a; http://spring.io/ &#xff09;&#xff0c;它由Rod Johnson创为了解决企业级编程开发的复杂性而创建 1.2.简化应用开发体现在哪些方面&#xff1f; IOC 解决传统Web开发中硬编…

【MATLAB】EEMD_LSTM神经网络时序预测算法

有意向获取代码&#xff0c;请转文末观看代码获取方式~也可转原文链接获取~ 1 基本定义 EEMD-LSTM神经网络时序预测算法是一种结合了扩展经验模态分解&#xff08;EEMD&#xff09;和长短期记忆神经网络&#xff08;LSTM&#xff09;的时间序列预测方法。 EEMD是一种改进的EM…

spring见解2基于注解的IOC配置

3.基于注解的IOC配置 学习基于注解的IOC配置&#xff0c;大家脑海里首先得有一个认知&#xff0c;即注解配置和xml配置要实现的功能都是一样的&#xff0c;都是要降低程序间的耦合。只是配置的形式不一样。 3.1.创建工程 3.1.1.pom.xml <?xml version"1.0" en…
最新文章