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.mzph.cn/news/888169.shtml

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

相关文章

OGRE 3D----5. OGRE和QML事件交互

在现代图形应用程序开发中,OGRE(Object-Oriented Graphics Rendering Engine)作为一个高性能的3D渲染引擎,广泛应用于游戏开发、虚拟现实和仿真等领域。而QML(Qt Modeling Language)则是Qt框架中的一种声明式语言,专注于设计用户界面。将OGRE与QML结合,可以充分利用OGR…

mysql系列2—InnoDB数据存储方式

背景 本文将深入探讨InnoDB的底层存储机制&#xff0c;包括行格式、页结构、页目录以及表空间等核心概念。通过全面了解这些基础概念&#xff0c;有助于把握MySQL的存储架构&#xff0c;也为后续深入讨论MySQL的索引原理和查询优化策略奠定了基础。 1.行格式 mysql中数据以行…

matlab2024a安装

1.开始安装 2.点击安装 3.选择安装密钥 4.接受条款 5.安装密钥 21471-07182-41807-00726-32378-34241-61866-60308-44209-03650-51035-48216-24734-36781-57695-35731-64525-44540-57877-31100-06573-50736-60034-42697-39512-63953 6 7.选择许可证文件 8.找许可证文件 9.选…

交换机四大镜像(端口镜像、流镜像、VLAN镜像、MAC镜像)应用场景、配置实例及区别对比

在网络管理中&#xff0c;端口镜像、流镜像、VLAN镜像和MAC镜像都是用于监控和分析网络流量的重要技术。 端口镜像&#xff08;Port Mirroring&#xff09; 定义&#xff1a;端口镜像是将一个或多个源端口的流量复制到一个目标端口&#xff0c;以便于网络管理员能够监控和分析…

JVM知识点学习-1

学习视频&#xff1a;狂神说Java 类加载器和双亲委派机制 类加载器 作用&#xff1a;加载Class文件 流程&#xff1a;这里的名字car1。。在栈里面&#xff0c;但是数据在堆里面 类加载器的几个类型&#xff1a; 虚拟机自带的类加载器&#xff1b;启动类&#xff08;根Boot…

Linux下的三种 IO 复用

目录 一、Select 1、函数 API 2、使用限制 3、使用 Demo 二、Poll 三、epoll 0、 实现原理 1、函数 API 2、简单代码模板 3、LT/ET 使用过程 &#xff08;1&#xff09;LT 水平触发 &#xff08;2&#xff09;ET边沿触发 4、使用 Demo 四、参考链接 一、Select 在…

python学习笔记 - python安装与环境变量配置

目录 前言1. 版本选择1.1 什么版本合适&#xff1f;1.2 版本越新越好吗&#xff1f;1.3 维护中的大版本里&#xff0c;选择最早的好吗&#xff1f;1.4 我的选择1.5 Python 发布周期1.6 Python维护中的版本及截止时间 2. 安装包下载2.1 官网地址2.2 下载安装包3. 环境安装3.1 新…

管理表空间和数据文件(二)

只读表空间 使用以下命令将表空间设置为只读模式&#xff1a; ALTER TABLESPACE userdata READ ONLY;必须等到TABLESPACE所有的过程都commit&#xff1b;才能可以执行成功。 导致检查点 Causes a checkpoint 意思是将内存中的数据&#xff08;如缓冲区中的更改&#xff09;写…

解决el-card上绑定@click事件,点击无效

解决&#xff1a; 在click后面加一个.native的修饰符即可 解释&#xff1a; .native 修饰符的作用&#xff1a;告诉 Vue&#xff0c;在绑定事件时&#xff0c;使用原生的 DOM 事件&#xff0c;而不是 Vue 自定义的事件。 因为 el-card 作为一个 Element UI 组件&#xff0c;默认…

AD7606使用方法

AD7606是一款8通道最高16位200ksps的AD采样芯片。5V单模拟电源供电&#xff0c;真双极性模拟输入可以选择10 V&#xff0c;5 V两种量程。支持串口与并口两种读取方式。 硬件连接方式&#xff1a; 配置引脚 引脚功能 详细说明 OS2 OS1 OS2 过采样率配置 000 1倍过采样率 …

蓝桥-希尔排序模板题

第一眼看到这个题还在想希尔排序模板不记得了&#xff0c;于是去网上了搜了一个&#xff0c;但是考虑到这种题只看测试点能不能通过&#xff0c;于是用Arrays方法试了一下&#xff0c;发现也可以。 1.希尔排序模板ac代码 package yunkePra;import java.util.Scanner;public cl…

机器学习6_支持向量机_算法流程

最大化&#xff1a; 限制条件&#xff1a; &#xff08;1&#xff09; &#xff08;2&#xff09; 如何求解这个对偶问题&#xff0c;同时基于对偶问题给出支持向量机算法的统一流程。 (核函数) 只要知道核函数&#xff0c;就可以求个这个最优化的对偶问题。 求解了这个对偶…

【WRF-Urban】城市冠层参数UCPs导入WPS/WRF中

城市冠层参数UCPs导入WPS/WRF中 Urban canopy parameters ingestion into WPS/ WRF关于建筑高度分布的分组数量GEOGRID.TBL 文件的配置是否需要修改 Registry 文件其他建议 参考 本博客主要总结WRF&MPAS-Aforum中有关城市冠层参数UCPs导入WPS/WRF的相关内容。原文章地址-Ur…

利用Python爬虫精准获取淘宝商品详情的深度解析

在数字化时代&#xff0c;数据的价值日益凸显&#xff0c;尤其是在电子商务领域。淘宝作为中国最大的电商平台之一&#xff0c;拥有海量的商品数据&#xff0c;对于研究市场趋势、分析消费者行为等具有重要意义。本文将详细介绍如何使用Python编写爬虫程序&#xff0c;精准获取…

Rook入门:打造云原生Ceph存储的全面学习路径(上)

文章目录 一.Rook简介二.Rook与Ceph架构2.1 Rook结构体系2.2 Rook包含组件2.3 Rook与kubernetes结合的架构图如下2.4 ceph特点2.5 ceph架构2.6 ceph组件 三.Rook部署Ceph集群3.1 部署条件3.2 获取rook最新版本3.3 rook资源文件目录结构3.4 部署Rook/CRD/Ceph集群3.5 查看rook部…

003 LVGL相关文件分析

LVGL移植相关文件&#xff1a; 显示设备接口文件 lv_port_disp_templ.c/输入设备接口文件 lv_port_indev_templ.c/h 裁剪、配置文件 lv_conf.h lv_conf.h文件内容介绍&#xff1a; 对应中文翻译版本&#xff1a; #if 1 /* 设置为1&#xff0c;以启…

汽车轮毂结构分析有哪些?国产3D仿真分析实现静力学+模态分析

本文为CAD芯智库原创&#xff0c;未经允许请勿复制、转载&#xff01; 之前分享了如何通过国产三维CAD软件如何实现「汽车/汽配行业产品设计」&#xff0c;兼容NX&#xff08;UG&#xff09;、Creo&#xff08;Proe&#xff09;&#xff0c;轻松降低企业上下游图纸交互成本等。…

关于Vscode配置Unity环境时的一些报错问题(持续更新)

第一种报错&#xff1a; 下载net请求超时&#xff08;一般都会超时很正常的&#xff09; 实际时并不需要解决&#xff0c;它对你的项目毫无影响 第二种报错&#xff1a; .net版本不匹配 解决&#xff1a;&#xff08;由于造成问题不一样&#xff0c;所以建议都尝试一次&…

iQOO Neo10系列携三大蓝科技亮相,性能与续航全面升级

11月29日&#xff0c;iQOO Neo10系列正式登场。作为iQOO Neo系列的最新力作&#xff0c;Neo10系列不仅延续了该系列一贯的“双芯”特色&#xff0c;更在性能、续航、屏幕、影像等多个方面实现了全面升级&#xff0c;为用户带来前所未有的使用体验。此次发布的Neo10系列共有两款…

NGO-CNN-BiGRU-Attention北方苍鹰算法优化卷积双向门控循环单元时间序列预测,含优化前后对比

NGO-CNN-BiGRU-Attention北方苍鹰算法优化卷积双向门控循环单元时间序列预测&#xff0c;含优化前后对比 目录 NGO-CNN-BiGRU-Attention北方苍鹰算法优化卷积双向门控循环单元时间序列预测&#xff0c;含优化前后对比预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介…