unity中:Unity 中异步与协程结合实现线程阻塞的http数据请求

在 Unity 开发中,将协程与 C# 的 async/await 机制结合,可以显著提高代码的可读性与维护性,并且支持返回值。


异步与协程结合在数据请求中的优势

  1. 提高代码可读性

    • 与传统协程相比, async/await 更接近同步逻辑,减少嵌套和复杂控制流。
  2. 支持返回值

    • 协程本身不能直接返回值,而通过异步与协程结合,可以轻松的在当前帧返回请求结果,而不是等待回调。
  3. 便于扩展

    • 例如,开发者可以轻松地在 GetPost 方法中加入身份验证、错误重试等逻辑,而无需修改协程的底层实现。

协程与异步结合的实现

核心方法:GetOrPostDataA
private async Task<string> GetOrPostDataA(string URL, Dictionary<string, string> body = null)
{var taskCompletionSource = new TaskCompletionSource<string>();var result = "";StartCoroutine(ExecuteRequest(URL, body, result, taskCompletionSource));// 等待协程完成return await taskCompletionSource.Task;
}
  • 功能:将协程 ExecuteRequest 的结果转换为异步任务。

  • 关键逻辑

    1. 创建 TaskCompletionSource 对象,用于管理异步任务的完成状态。
    2. 启动协程执行实际的 HTTP 请求。
    3. 使用 await taskCompletionSource.Task 挂起当前方法,等待协程完成。
  • 异步与协程结合点

    • TaskCompletionSource 是桥梁,协程通过 SetResult 通知异步任务完成,从而实现协程与 async/await 的结合。

协程实现:ExecuteRequest
private IEnumerator ExecuteRequest(string URL, Dictionary<string, string> body, string result, TaskCompletionSource<string> taskCompletionSource)
{// 创建并发送请求var request = new HTTPRequest(new Uri(URL), body == null ? HTTPMethods.Get : HTTPMethods.Post).Send();if (body != null){MultipartFormDataStream data = new MultipartFormDataStream();foreach (var variable in body){data.AddField(variable.Key, variable.Value);}}// 等待请求完成while (request.State < HTTPRequestStates.Finished){yield return null;}// 检查请求结果switch (request.State){case HTTPRequestStates.Finished:if (request.Response.IsSuccess){result = request.Response.DataAsText;}else{result = $"Server error: {request.Response.StatusCode}";}break;case HTTPRequestStates.Error:result = $"Error: {request.Exception?.Message ?? "Unknown error"}";break;default:result = "Request failed or timed out.";break;}// 通知异步任务完成taskCompletionSource.SetResult(result);
}
  • 协程逻辑

    1. 使用 HTTPRequest 发起网络请求。
    2. 等待请求完成,期间每帧检查请求状态。
    3. 根据请求状态设置结果。
  • 与异步任务的结合

    • 在协程末尾,通过 taskCompletionSource.SetResult 将结果传递给异步任务,从而完成任务。

使用示例

1. GET 请求示例

async void PerformGetRequest()
{string url = "https://example.com/api/resource";string response = await HttpHelper.Instance.Get(url);Debug.Log("GET Response: " + response);
}

2. POST 请求示例

async void PerformPostRequest()
{string url = "https://example.com/api/resource";Dictionary<string, string> parameters = new Dictionary<string, string>{{ "username", "testuser" },{ "password", "123456" }};string response = await HttpHelper.Instance.Post(url, parameters);Debug.Log("POST Response: " + response);
}

完整代码如下

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using Best.HTTP;
using Best.HTTP.Request.Upload.Forms;
using UnityEngine;public sealed class HttpHelper : MonoBehaviour
{// 单例实例private static HttpHelper _instance;// 线程锁,确保线程安全private static readonly object Lock = new object();// 公共访问接口public static HttpHelper Instance{get{lock (Lock){if (_instance == null){// 查找是否有已有的实例_instance = FindObjectOfType<HttpHelper>();if (_instance == null){// 创建新的实例GameObject singletonObject = new GameObject();_instance = singletonObject.AddComponent<HttpHelper>();singletonObject.name = typeof(HttpHelper).ToString();// 确保单例不会被销毁DontDestroyOnLoad(singletonObject);}}return _instance;}}}// 防止通过构造函数创建实例private HttpHelper() { }public async Task<string> Get(string url, bool useToken = true){return await GetOrPostDataA(url);}public async Task<string> Post(string url, Dictionary<string,string> listParam = null, bool useToken = true){return await GetOrPostDataA(url, listParam);}private async Task<string> GetOrPostDataA(string URL, Dictionary<string,string> body = null){var taskCompletionSource = new TaskCompletionSource<string>();var result = "";StartCoroutine(ExecuteRequest(URL, body, result, taskCompletionSource));// 等待协程完成return await taskCompletionSource.Task;}private IEnumerator ExecuteRequest(string URL, Dictionary<string,string> body, string result, TaskCompletionSource<string> taskCompletionSource){string status = "";// 创建并发送请求var request = new HTTPRequest(new Uri(URL), body == null ? HTTPMethods.Get : HTTPMethods.Post).Send();if (body != null){MultipartFormDataStream data = new MultipartFormDataStream();foreach (var variable in body){data.AddField(variable.Key, variable.Value);}}// 等待请求完成while (request.State < HTTPRequestStates.Finished){yield return null;}// 检查请求结果switch (request.State){case HTTPRequestStates.Finished:if (request.Response.IsSuccess){Debug.Log(request.Response.DataAsText);// // 将响应数据保存到 E:/Data.json// try// {//     string filePath = "E:/Data.json";//     File.WriteAllText(filePath, request.Response.DataAsText);//     Debug.Log($"Response data saved to {filePath}");// }// catch (Exception ex)// {//     Debug.LogError($"Error saving response data to file: {ex.Message}");// }result = request.Response.DataAsText;}else{status = string.Format("Request finished Successfully, but the server sent an error. Status Code: {0}-{1} Message: {2}",request.Response.StatusCode,request.Response.Message,request.Response.DataAsText);Debug.LogWarning(status);result = status;}break;case HTTPRequestStates.Error:status = "Request Finished with Error! " + (request.Exception != null? (request.Exception.Message + "\n" + request.Exception.StackTrace): "No Exception");Debug.LogError(status);result = status;break;case HTTPRequestStates.Aborted:status = "Request Aborted!";Debug.LogWarning(status);result = status;break;case HTTPRequestStates.ConnectionTimedOut:status = "Connection Timed Out!";Debug.LogError(status);result = status;break;case HTTPRequestStates.TimedOut:status = "Processing the request Timed Out!";Debug.LogError(status);result = status;break;}// 通知任务完成taskCompletionSource.SetResult(result);}
}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

设计模式:11、迭代器模式(游标)

目录 0、定义 1、迭代器模式的四种角色 2、迭代器模式的UML类图 3、示例代码 4、迭代器的next()方法与集合的get(int index)方法的效率对比&#xff08;LinkedList为例&#xff09; 0、定义 提供一种方法顺序访问一个聚合对象中的各个元素&#xff0c;而又不需要暴露该对象…

Web开发基础学习——通过React示例学习模态对话框

Web开发基础学习系列文章目录 第一章 基础知识学习之通过React组件学习模态对话框 文章目录 Web开发基础学习系列文章目录前言一、创建新的 React 应用二、 创建模态对话框组件三、修改 App.js四、 添加样式五、启动应用六、访问应用总结 前言 模态对话框&#xff08;Modal D…

Unity XR Interaction Toolkit 开发教程:抓取交互【3.0以上版本】

获取完整课程以及答疑&#xff0c;工程文件下载&#xff1a; https://www.spatialxr.tech/ Unity XR Interaction Toolkit 系统化开发教程&#xff1a;https://www.spatialxr.tech/course/5 视频说明链接&#xff1a;抓取交互课程介绍【全球最新 Unity VR 系统化入门开发教程…

科技为翼 助残向新 高德地图无障碍导航规划突破1.5亿次

今年12月03日是第33个国际残疾人日。在当下科技发展日新月异的时代&#xff0c;如何让残障人士共享科技红利、平等地参与社会生活&#xff0c;成为当前社会关注的热点。 中国有超过8500万残障人士&#xff0c;其中超过2400万为肢残人群&#xff0c;视力障碍残疾人数超过1700万…

OGRE 3D----4. OGRE和QML共享opengl上下文

在现代图形应用开发中,OGRE(Object-Oriented Graphics Rendering Engine)和QML(Qt Modeling Language)都是非常流行的工具。OGRE提供了强大的3D渲染能力,而QML则用于构建灵活的用户界面。在某些应用场景中,我们需要在同一个应用程序中同时使用OGRE和QML,并且共享OpenGL…

YOLOv9改进,YOLOv9引入TransNeXt中的ConvolutionalGLU模块,CVPR2024,二次创新RepNCSPELAN4结构

摘要 由于残差连接中的深度退化效应,许多依赖堆叠层进行信息交换的高效视觉Transformer模型往往无法形成足够的信息混合,导致视觉感知不自然。为了解决这个问题,作者提出了一种聚合注意力(Aggregated Attention),这是一种基于仿生设计的token混合器,模拟了生物的中央凹…

坐标系变换

1 Clark变换 三相对称电压表达式为&#xff1a; 将三相电压用相量的形式表达出来&#xff0c;并用欧拉公式&#xff08;eix(cosxisinx)&#xff09;写成三角函数的形式&#xff1a; 同时&#xff0c;三相电压矢量空间合成向量可表示为&#xff1a; 三相电压合成矢量幅值为相电…

Java 上机实践10(常用实用类)

&#xff08;大家好&#xff0c;今天分享的是Java的相关知识&#xff0c;大家可以在评论区进行互动答疑哦~加油&#xff01;&#x1f495;&#xff09; 目录 Plug&#xff1a;程序实现方法一&#xff08;记事本&#xff09; 方法二&#xff08;IDEA&#xff09; 实验一&…

【JavaEE初阶 — 网络编程】Socket 套接字 & UDP数据报套接字编程

1. Socket套接字 1.1 概念 Socket 套接字&#xff0c;是由系统提供用于网络通信的技术&#xff0c;是基于TCP / IP协议的网络通信的基本操作单元。基于 Socket 套接字的网络程序开发就是网络编程。 1.2 分类 Socket套接字主要针对传输层协议划分为如下三类&#x…

MacOS 如何连接 Linux NFS 服务器

以 Ubuntu 为例。 Ubuntu 服务器端设置 1. 进入 root 权限&#xff0c;安装 NFS 服务&#xff1a; apt-get update apt-get install nfs-kernel-server2. 创建共享目录&#xff1a; mkdir /data chown nobody:nogroup /data chmod 777 /data3. 配置 /etc/exports 文件: vi …

23种设计模式-原型(Prototype)设计模式

文章目录 一.什么是原型设计模式&#xff1f;二.原型模式的特点三.原型模式的结构四.原型模式的优缺点五.原型模式的 C 实现六.原型模式的 Java 实现七. 代码解析八.总结 类图&#xff1a; 原型设计模式类图 一.什么是原型设计模式&#xff1f; 原型模式&#xff08;Prototype…

Docker Buildx 与 CNB 多平台构建实践

一、Docker Buildx 功能介绍 docker buildx 是 Docker 提供的一个增强版构建工具&#xff0c;支持更强大的构建功能&#xff0c;特别是在构建多平台镜像和高效处理复杂 Docker 镜像方面。 1.1 主要功能 多平台构建支持 使用 docker buildx&#xff0c;可以在单台设备上构建…

C# 数据类型详解:掌握数据类型及操作为高效编码奠定基础

本文将带你深入了解C#中各种数据类型的特点、用途和最佳实践&#xff0c;让你不仅能熟练运用基本类型&#xff0c;还能掌握如何在实际项目中做出最合适的选择。 目录 C#基本语法 C#数据类型 C#类型转换 C#变量常量 C#基本语法 在学习C#之前我们要先知道C#的基础构建是由哪些…

新型大语言模型的预训练与后训练范式,谷歌的Gemma 2语言模型

前言&#xff1a;大型语言模型&#xff08;LLMs&#xff09;的发展历程可以说是非常长&#xff0c;从早期的GPT模型一路走到了今天这些复杂的、公开权重的大型语言模型。最初&#xff0c;LLM的训练过程只关注预训练&#xff0c;但后来逐步扩展到了包括预训练和后训练在内的完整…

Istio笔记01--快速体验Istio

Istio笔记01--快速体验Istio 介绍部署与测试部署k8s安装istio测试istio 注意事项说明 介绍 Istio是当前最热门的服务网格产品&#xff0c;已经被广泛应用于各个云厂商和IT互联网公司。企业可以基于Istio轻松构建服务网格&#xff0c;在接入过程中应用代码无需更改&#xff0c;…

uniapp运行时,同步资源失败,未得到同步资源的授权,请停止运行后重新运行,并注意手机上的授权提示。

遇到自定义基座调试时安装无效或无反应&#xff1f;本文教你用 ADB 工具快速解决&#xff1a;打开 USB 调试&#xff0c;连接设备&#xff0c;找到应用包名&#xff0c;一键卸载问题包&#xff0c;清理干净后重新运行调试基座&#xff0c;轻松搞定&#xff01; 问题场景&#…

CAD 文件 批量转为PDF或批量打印

CAD 文件 批量转为PDF或批量打印&#xff0c;还是比较稳定的 1.需要本地安装CAD软件 2.通过 Everything 搜索工具搜索&#xff0c;DWG To PDF.pc3 &#xff0c;获取到文件目录 &#xff0c;替换到代码中&#xff0c; originalValue ACADPref.PrinterConfigPath \ r"C:…

蓝桥杯每日真题 - 第23天

题目&#xff1a;&#xff08;直线&#xff09; 题目描述&#xff08;12届 C&C B组C题&#xff09; 解题思路&#xff1a; 题目理解: 在平面直角坐标系中&#xff0c;从给定的点集中确定唯一的直线。 两点确定一条直线&#xff0c;判断两条直线是否相同&#xff0c;可通过…

centos8:Could not resolve host: mirrorlist.centos.org

【1】错误消息&#xff1a; [rootcentos211 redis-7.0.15]# yum update CentOS Stream 8 - AppStream …

Android笔记(三十四):封装带省略号图标结尾的TextView

背景 项目需求需要实现在文本末尾显示一个icon&#xff0c;如果文本很长时则在省略号后面显示icon&#xff0c;使用TextView自带的drawableEnd可以实现&#xff0c;但是如果文本换行了则会显示在TextView垂直居中的位置&#xff0c;不满足要求&#xff0c;于是有了本篇的自定义…