Last active
April 19, 2024 11:34
-
-
Save lightjiao/30bf01cfcdf7ed2bb989017e8e98e7b0 to your computer and use it in GitHub Desktop.
基于 UniTask 的支持并发的 Http 库
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Cysharp.Threading.Tasks; | |
using System.Collections.Generic; | |
using UnityEngine.LowLevel; | |
using UnityEngine.Networking; | |
namespace UniHttpLib | |
{ | |
public class UniHttp | |
{ | |
private static UniHttp m_Inst; | |
public static UniHttp Inst | |
{ | |
get | |
{ | |
if (m_Inst == null) m_Inst = new UniHttp(); | |
return m_Inst; | |
} | |
} | |
private bool m_Init = false; | |
private UniHttp() | |
{ | |
Init(); | |
} | |
public void Init() | |
{ | |
if (m_Init) return; | |
m_Init = true; | |
var uniHttpLoopSystem = new PlayerLoopSystem | |
{ | |
type = typeof(UniHttp), | |
updateDelegate = Update, | |
}; | |
var playerLoop = | |
#if UNITY_2019_3_OR_NEWER | |
PlayerLoop.GetCurrentPlayerLoop(); | |
#else | |
PlayerLoop.GetDefaultPlayerLoop(); | |
#endif | |
for (int i = 0; i < playerLoop.subSystemList.Length; i++) | |
{ | |
if (playerLoop.subSystemList[i].type == typeof(UnityEngine.PlayerLoop.PreLateUpdate)) | |
{ | |
var subSystems = playerLoop.subSystemList[i].subSystemList; | |
var newSubsystem = new PlayerLoopSystem[subSystems.Length + 1]; | |
subSystems.CopyTo(newSubsystem, 0); | |
newSubsystem[subSystems.Length] = uniHttpLoopSystem; | |
playerLoop.subSystemList[i].subSystemList = newSubsystem; | |
break; | |
} | |
} | |
PlayerLoop.SetPlayerLoop(playerLoop); | |
} | |
private class UniHttpReq | |
{ | |
private static Stack<UniHttpReq> m_Pool = new Stack<UniHttpReq>(); | |
public static UniHttpReq Acquire() | |
{ | |
if (m_Pool.Count > 0) return m_Pool.Pop(); | |
return new UniHttpReq(); | |
} | |
public int UrlHashCode; | |
public UnityWebRequest Req; | |
public AutoResetUniTaskCompletionSource<object> Tcs; | |
public List<AutoResetUniTaskCompletionSource<object>> TcsArr; | |
private void Release() | |
{ | |
TcsArr?.Clear(); | |
TcsArr = null; | |
Tcs = null; | |
Req = null; | |
m_Pool.Push(this); | |
} | |
public void AppendTcs(AutoResetUniTaskCompletionSource<object> tcs) | |
{ | |
if (TcsArr == null) TcsArr = new List<AutoResetUniTaskCompletionSource<object>>(); | |
TcsArr.Add(tcs); | |
} | |
public void TrySetResult(object obj) | |
{ | |
Tcs.TrySetResult(obj); | |
if (TcsArr != null) | |
{ | |
foreach (var item in TcsArr) | |
{ | |
item.TrySetResult(obj); | |
} | |
} | |
Release(); | |
} | |
} | |
private Queue<UniHttpReq> m_Queue = new(); | |
private Dictionary<int, UniHttpReq> m_Map = new(); | |
private int m_GCTimer = 0; | |
private void Update() | |
{ | |
if (m_Queue.Count == 0) | |
{ | |
return; | |
} | |
var currentReq = m_Queue.Peek(); | |
if (currentReq.Req.isDone) | |
{ | |
m_Map.Remove(currentReq.UrlHashCode); | |
m_Queue.Dequeue(); | |
currentReq.TrySetResult(currentReq.Req.downloadHandler.data); | |
} | |
m_GCTimer++; | |
if (m_GCTimer >= 1000) | |
{ | |
m_GCTimer = 0; | |
m_Queue.TrimExcess(); | |
m_Map.TrimExcess(); | |
} | |
} | |
public UniTask<object> RequestAsync(string url) | |
{ | |
var urlHashCode = url.GetHashCode(); | |
var tcs = AutoResetUniTaskCompletionSource<object>.Create(); | |
if (m_Map.ContainsKey(urlHashCode)) | |
{ | |
m_Map[urlHashCode].AppendTcs(tcs); | |
return tcs.Task; | |
} | |
var http = new UnityWebRequest(); | |
http.url = url; | |
http.method = "GET"; | |
http.downloadHandler = new DownloadHandlerBuffer(); | |
http.SendWebRequest(); | |
var uniReq = UniHttpReq.Acquire(); | |
uniReq.UrlHashCode = urlHashCode; | |
uniReq.Req = http; | |
uniReq.Tcs = tcs; | |
m_Queue.Enqueue(uniReq); | |
m_Map[uniReq.UrlHashCode] = uniReq; | |
return tcs.Task; | |
} | |
} | |
} |
Author
lightjiao
commented
Apr 3, 2024
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment