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

news/2024/11/28 10:02:40/
http://www.w3.org/2000/svg" style="display: none;">

在 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.ppmy.cn/news/1550584.html

相关文章

【linux】Linux内核和应用层常见的通信方式及举例整理

Linux内核和应用层常见的通信方式 系统调用&#xff08;System Calls&#xff09; 应用程序通过系统调用与内核进行交互。这是最基本的通信方式&#xff0c;应用程序可以通过系统调用请求内核提供的服务&#xff0c;如文件操作、进程控制等。 proc文件系统 /proc文件系统提供…

hping3工具介绍及使用方法

文章目录 hping3 的特点hping3 的常见功能1. 发送 ICMP 请求&#xff08;类似 ping&#xff09;2. TCP SYN 扫描3. SYN 洪水攻击4. TCP ACK 扫描5. UDP 洪水攻击6. 模拟 IP 欺骗7. 自定义数据包8. ICMP 路由追踪9. Ping 洪水攻击 总结 hping3 是一个强大的命令行网络工具&#…

如何评估爬虫获取的数据质量?

评估爬虫获取的数据质量是一个多维度的过程&#xff0c;涉及到数据的完整性、准确性、时效性等多个方面。以下是一些关键的评估标准和方法&#xff1a; 数据完整性评估&#xff1a; 缺失值处理&#xff1a;检查数据集中是否存在缺失值&#xff0c;并采取适当的方法进行处理&…

研0找实习【学nlp】14--BERT理解

​​​​​以后做项目&#xff0c;一定要多调查&#xff0c;选用不同组合关键词多搜索&#xff01; BERT论文解读及情感分类实战_bert模型在imdb分类上的准确率已经到达了多少的水平-CSDN博客 【深度学习】-Imdb数据集情感分析之模型对比&#xff08;4&#xff09;- CNN-LSTM…

VsCode 插件推荐(个人常用)

VsCode 插件推荐&#xff08;个人常用&#xff09;

欢迪迈手机商城:SpringBoot框架的持续集成

摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本欢迪迈手机商城就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在短时间内处理完毕庞大的数据信息&a…

心情追忆:构建支付模块的五个基本接口设计

之前&#xff0c;我独自一人开发了一个名为“心情追忆”的小程序&#xff0c;旨在帮助用户记录日常的心情变化及重要时刻。我从项目的构思、设计、前端&#xff08;小程序&#xff09;开发、后端搭建到最终部署。经过一个月的努力&#xff0c;通过群聊分享等方式&#xff0c;用…

【前端】JavaScript中的柯里化(Currying)详解及实现

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: 前端 文章目录 &#x1f4af;前言&#x1f4af;什么是柯里化&#xff1f;&#x1f4af;柯里化的特点&#x1f4af;柯里化的简单示例&#x1f4af;通用的柯里化实现&#x1f4af;柯里化让代码更易读的原因&#x1f4af…