/// <summary>执行命令</summary> /// <typeparam name="TResult">返回类型</typeparam> /// <param name="func">回调函数</param> /// <param name="write">是否写入操作</param> /// <returns></returns> public virtual TResult Execute <TResult>(Func <RedisClient, TResult> func, Boolean write = false) { // 写入或完全管道模式时,才处理管道操作 if (write || FullPipeline) { // 管道模式直接执行 var rds = _client.Value; if (rds == null && AutoPipeline > 0) { rds = StartPipeline(); } if (rds != null) { var rs = func(rds); // 命令数足够,自动提交 if (AutoPipeline > 0 && rds.PipelineCommands >= AutoPipeline) { StopPipeline(); StartPipeline(); } return(rs); } } // 统计性能 var sw = Counter?.StartCount(); var i = 0; do { // 每次重试都需要重新从池里借出连接 var client = Pool.Get(); try { client.Reset(); var rs = func(client); Counter?.StopCount(sw); return(rs); } catch (InvalidDataException) { if (i++ >= Retry) { throw; } } finally { Pool.Put(client); } } while (true); }
/// <summary>执行命令</summary> /// <typeparam name="T"></typeparam> /// <param name="func"></param> /// <returns></returns> public virtual T Execute <T>(Func <RedisClient, T> func) { var client = Pool.Get(); try { var i = 0; do { try { var rs = func(client); //// 如果返回Packet,需要在离开对象池之前拷贝,否则可能出现冲突 //if ((Object)rs is Packet pk) return (T)(Object)pk.Clone(); return(rs); } catch (InvalidDataException) { if (i++ >= Retry) { throw; } } } while (true); } finally { Pool.Put(client); } }
/// <summary> /// 2017-8-4 /// Lets the pool manager know to recycle the item. The appropriate pool is notified and the object /// is reset and deactivated. /// /// WARNING: if the item was renamed, this will probably fail (depending on whether GetInstanceID() /// uses the object name to generate the hashcode. When an item's hashcode cannot be found in /// the pool, the item is destroyed and the return value is false. /// </summary> public static bool Put(GameObject item) { bool result = false; foreach (var p in pools) { IPool pool = p.Value; result = pool.Put(item); if (result) { break; } } if (!result) { if (Application.isEditor) { MonoBehaviour.DestroyImmediate(item); } else { MonoBehaviour.Destroy(item); } } return(result); }
/// <summary>访问地址获取字符串</summary> /// <param name="address"></param> /// <returns></returns> public static async Task <String> GetStringAsync(String address) { var client = Pool.Get(); try { return(await client.DownloadStringAsync(address)); } finally { Pool.Put(client); } }
/// <summary>执行命令</summary> /// <typeparam name="TResult">返回类型</typeparam> /// <param name="key">命令key,用于选择集群节点</param> /// <param name="func">回调函数</param> /// <param name="write">是否写入操作</param> /// <returns></returns> public virtual TResult Execute <TResult>(String key, Func <RedisClient, TResult> func, Boolean write = false) { using var span = Tracer?.NewSpan($"redis:{(write ? "write" : "read")}"); if (span != null) { span.Tag = key; } // 写入或完全管道模式时,才处理管道操作 if (write || FullPipeline) { // 管道模式直接执行 var rds = _client.Value; if (rds == null && AutoPipeline > 0) { rds = StartPipeline(); } if (rds != null) { var rs = func(rds); // 命令数足够,自动提交 if (AutoPipeline > 0 && rds.PipelineCommands >= AutoPipeline) { StopPipeline(true); StartPipeline(); } return(rs); } } // 读操作遇到未完成管道队列时,立马执行管道操作 if (!write) { StopPipeline(true); } // 统计性能 var sw = Counter?.StartCount(); var i = 0; do { // 每次重试都需要重新从池里借出连接 var client = Pool.Get(); try { client.Reset(); return(func(client)); } catch (InvalidDataException) { if (i++ >= Retry) { throw; } } finally { Pool.Put(client); Counter?.StopCount(sw); } } while (true); }
/// <summary>执行命令</summary> /// <typeparam name="TResult">返回类型</typeparam> /// <param name="key">命令key,用于选择集群节点</param> /// <param name="func">回调函数</param> /// <param name="write">是否写入操作</param> /// <returns></returns> public virtual TResult Execute <TResult>(String key, Func <RedisClient, TResult> func, Boolean write = false) { // 写入或完全管道模式时,才处理管道操作 if (write || FullPipeline) { // 管道模式直接执行 var rds = _client.Value; if (rds == null && AutoPipeline > 0) { rds = StartPipeline(); } if (rds != null) { var rs = func(rds); // 命令数足够,自动提交 if (AutoPipeline > 0 && rds.PipelineCommands >= AutoPipeline) { StopPipeline(true); StartPipeline(); } return(rs); } } // 读操作遇到未完成管道队列时,立马执行管道操作 if (!write) { StopPipeline(true); } // 统计性能 var sw = Counter?.StartCount(); var i = 0; do { // 每次重试都需要重新从池里借出连接 var client = Pool.Get(); try { client.Reset(); return(func(client)); } catch (InvalidDataException) { if (i++ >= Retry) { throw; } Thread.Sleep(100); } catch (Exception ex) { if (ex is SocketException || ex is IOException) { // 销毁连接 client.TryDispose(); // 网络异常时,自动切换到其它节点 _idxServer++; if (++i < _servers.Length) { Thread.Sleep(100); continue; } } throw; } finally { Pool.Put(client); Counter?.StopCount(sw); } } while (true); }
/// <summary>Starts the loading, setting the current image to <see cref="_LoadingTexture"/>, if available. If the image is already in cache, and <paramref name="loadCachedIfAvailable"/>==true, will load that instead</summary> public void Load(string imageURL, bool loadCachedIfAvailable = true, LoadCompleteDelegate onCompleted = null, Action onCanceled = null) { bool currentRequestedURLAlreadyLoaded = _CurrentRequestedURL == imageURL; _CurrentRequestedURL = imageURL; if (loadCachedIfAvailable) { bool foundCached = false; // Don't re-request if the url is the same. This is useful if there's no pool provided if (currentRequestedURLAlreadyLoaded) { foundCached = _Texture != null; } else if (_Pool != null) { Texture2D cachedInPool = _Pool.Get(imageURL) as Texture2D; if (cachedInPool) { _Texture = cachedInPool; foundCached = true; _CurrentRequestedURL = imageURL; } } if (foundCached) { _RawImage.texture = _Texture; if (onCompleted != null) { onCompleted(true, true); } return; } } _RawImage.texture = _LoadingTexture; var request = new SimpleImageDownloader.Request() { url = imageURL, onDone = result => { if (!_DestroyPending && imageURL == _CurrentRequestedURL) // this will be false if a new request was done during downloading, case in which the result will be ignored { // Commented: not reusing textures to load data into them anymore, since in most cases we'll use a pool //result.LoadTextureInto(_Texture); if (_Pool == null) { // Non-pooled textures should be destroyed if (_Texture) { DisposeTexture(_Texture); } _Texture = result.CreateTextureFromReceivedData(); } else { var textureAlreadyStoredMeanwhile = _Pool.Get(imageURL); bool someoneStoredTheImageSooner = textureAlreadyStoredMeanwhile != null; if (someoneStoredTheImageSooner) { // Happens when the same URL is requested multiple times for the first time, and of course only the first // downloaded image should be kept. In this case, someone else already have downloaded and cached the image, so we just discard the one we downloaded _Texture = textureAlreadyStoredMeanwhile as Texture2D; } else { // First time downloaded => cache _Texture = result.CreateTextureFromReceivedData(); _Pool.Put(imageURL, _Texture); } } _RawImage.texture = _Texture; if (onCompleted != null) { onCompleted(false, true); } } else if (onCanceled != null) { onCanceled(); } }, onError = () => { if (!_DestroyPending && imageURL == _CurrentRequestedURL) // this will be false if a new request was done during downloading, case in which the result will be ignored { _RawImage.texture = _ErrorTexture; if (onCompleted != null) { onCompleted(false, false); } } else if (onCanceled != null) { onCanceled(); } } }; SimpleImageDownloader.Instance.Enqueue(request); }