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

news2025/4/7 16:26:52

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.coloradmin.cn/o/1356317.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MySQL自定义时间间隔抽稀

MySQL自定义时间间隔抽稀 表设计数据如下按分钟抽稀按小时抽稀按天抽稀 表设计 create table monitor (tid varchar(255) not null,save_date datetime not null,tlevel decimal(10, 2) null,primary key (tid, save_date) );数据如下 按分钟抽稀 SELECT t2…

FLatten Transformer:聚焦式线性注意力模块

线性注意力将Softmax解耦为两个独立的函数&#xff0c;从而能够将注意力的计算顺序从(querykey)value调整为query(keyvalue)&#xff0c;使得总体的计算复杂度降低为线性。然而&#xff0c;目前的线性注意力方法要么性能明显不如Softmax注意力&#xff0c;并且可能涉及映射函数…

webapp下没有蓝点解决

解决方法&#xff1a; File->Project Structure 现在就是一个JavaWeb项目了。

华为云CES监控与飞书通知

华为云负载均衡连接数监控与飞书通知 在云服务的日常运维中&#xff0c;持续监控资源状态是保障系统稳定性的关键步骤之一。本文通过一个实际案例展示了如何使用华为云的Go SDK获取负载均衡器的连接数&#xff0c;并通过飞书Webhook发送通知到团队群组&#xff0c;以便运维人员…

2024 Nomachine 最简安装与使用指南

一、前言 二、Nomachine安装包的下载 1、Windows系统下Nomachine包的下载 2、Linux系统Nomachine的下载 &#xff08;1&#xff09;下载Nomachine安装包 &#xff08;2&#xff09;解压安装包 &#xff08;3&#xff09;添加权限 &#xff08;4&#xff09;下载安装包 三、在Wi…

基于GEC6818的点餐系统

本次项目开发环境&#xff1a;gec6818&#xff0c;QT5.14.2&#xff0c;SecureCRT。 所使用的相关技术&#xff1a;c/s架构&#xff0c;STL库&#xff0c;C封装&#xff0c;标准化代码编写 实现的功能&#xff1a;用户登录页面&#xff0c;食品分区在不同页面&#xff0c;用户…

2023海内外零知识证明学习资料汇总(二)(深入理解零知识证明篇)

工欲善其事,必先利其器 Web3开发中&#xff0c;各种工具、教程、社区、语言框架.。。。 种类繁多&#xff0c;是否有一个包罗万象的工具专注与Web3开发和相关资讯能毕其功于一役&#xff1f; 参见另一篇博文&#x1f449; 2024最全面且有知识深度的web3开发工具、web3学习项目…

Java中关键词strictfp有什么作用?

在Java中&#xff0c;关键词strictfp用于声明一个方法、类或接口是严格遵守浮点数计算规范的。 具体作用包括&#xff1a; 保证浮点数计算的结果在不同平台上是一致的&#xff0c;避免由于浮点数计算的不精确性导致的结果不确定性。 指定了严格的浮点数计算规则&#xff0c;禁…

【机器学习基础】DBSCAN

&#x1f680;个人主页&#xff1a;为梦而生~ 关注我一起学习吧&#xff01; &#x1f4a1;专栏&#xff1a;机器学习 欢迎订阅&#xff01;相对完整的机器学习基础教学&#xff01; ⭐特别提醒&#xff1a;针对机器学习&#xff0c;特别开始专栏&#xff1a;机器学习python实战…

springboot实现用户操作日志记录

springboot实现用户操作日志记录 简介&#xff1a;之前写了《aop实现日志持久化记录》一文&#xff0c;主要介绍自定义aop标注方法上&#xff0c;通过切面方法对用户操作插入mysql。思路正确但是实际操作上存在一些小问题&#xff0c;本文将从项目出发&#xff0c;对细节进行补…

vue3+vant4 移动端软键盘弹出 收起导致项目样式布局错乱解决方案,亲测有效!!

问题描述 最近在做vue3 H5的移动端项目 我用的是vue3vant4&#xff0c;然后在使用过程中发现 小米14手机在点击密码输入框软键盘弹出 时会导致项目布局整体向上移动 导致页面布局错乱。 原因分析&#xff1a; 在移动端软键盘弹出收起时&#xff0c;导致项目样式布局错乱的原因…

内网DNS隐蔽隧道搭建之iodine工具

iodine iodine是基于C语言开发的&#xff0c;分为服务端和客户端。iodine支持转发模式和中继模式。其原理是&#xff1a;通过TAP虚拟网卡&#xff0c;在服务端建立一个局域网&#xff1b;在客户端&#xff0c;通过TAP建立一个虚拟网卡&#xff1b;两者通过DNS隧道连接&#xf…

前端开发加速器:十个VSCode插件精选

前端开发是一个不断发展的领域&#xff0c;随着技术的进步&#xff0c;工具也在不断更新。Visual Studio Code&#xff08;VSCode&#xff09;是前端开发者广泛使用的编辑器之一&#xff0c;得益于其强大的插件系统&#xff0c;可以帮助开发者提升工作效率。以下是十个对于前端…

任务需求分析中的流程图、用例图、er图、类图、时序图线段、图形的作用意义

任务需求分析中的流程图、用例图、er图、类图、时序图线段、图形的作用意义 流程图 流程图中各种图形的含义及用法解析 连接线符号 连接各要素&#xff0c;表示流程的顺序或过程的方向。 批注符号 批注或说明&#xff0c;也可以做条件叙述。 子流程 流程中一部分图形的逻辑…

程序员如何应对裁员-法律知识

目录 程序员如何应对裁员-法律知识 前言收到辞退消息后被要求主动离职可以赔偿多少呢裁员赔偿工资是指基本工资吗被强制接触劳动合同&#xff0c;也不愿意支付赔偿孕妇&#xff0c;公司让离职谈话之后&#xff0c;老板还是不愿意给补偿&#xff0c;我应该怎么办&#xff1f;离…

IO作业4.0

思维导图 创建出三个进程完成两个文件之间拷贝工作&#xff0c;子进程1拷贝前一半内容&#xff0c;子进程2拷贝后一半内容&#xff0c;父进程回收子进程的资源 #include <stdio.h> #include <string.h> #include <stdlib.h> #include <myhead.h> int …

CCNP课程实验-07-OSPF-Trouble-Shooting

目录 实验条件网络拓朴 环境配置开始排错错点1&#xff1a;R1-R2之间认证不匹配错误2&#xff1a;hello包的时间配置不匹配错误3&#xff1a;R2的e0/1接口区域配置不正确错误4&#xff1a;R4的e0/1接口没有配置进OSPF错误5&#xff1a;R2的区域1没有配置成特殊区域错误6&#x…

ASP.NETCore WebAPI 入门 杨中科

ASP.NETCore WebAPI入门1 回顾 mvc开发模式 前端代码和后端代码是混在一个项目之中 WEB API 1、什么是结构化的Http接口。Json。 2、Web API项目的搭建。 3、Web API项目没有Views文件夹。 4、运行项目&#xff0c;解读代码结构。 5、【启用OpenAPI支持】→>swagger,在界…

Pytorch从零开始实战15

Pytorch从零开始实战——ResNeXt-50算法实战 本系列来源于365天深度学习训练营 原作者K同学 文章目录 Pytorch从零开始实战——ResNeXt-50算法实战环境准备数据集模型选择开始训练可视化总结 环境准备 本文基于Jupyter notebook&#xff0c;使用Python3.8&#xff0c;Pytor…

高效分割视频:批量剪辑,轻松提取m3u8视频技巧

在数字媒体时代&#xff0c;视频分割是一项常见的需求。无论是为了编辑、分享还是其他要求&#xff0c;经常要将长视频分割成多个短片。传统的视频分割方法往往需要手动操作&#xff0c;既耗时又容易出错。现在来看云炫AI智剪高效分割视频的方法&#xff0c;批量剪辑并轻松提取…