• HttpClientHelper


    //-------------------------------------------------------------------------- 
    //  
    //  Copyright (c) BUSHUOSX.  All rights reserved.  
    //  
    //  File: HttpClientHelper.cs 
    //
    //  Version:1.0.0.1
    //
    //  Datetime:20170815
    // 
    //-------------------------------------------------------------------------- 
    
    using System;
    using System.Collections.Concurrent;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Net.Http;
    using System.Threading;
    using System.Threading.Tasks;
    
    namespace BUSHUOSX.HTTP
    {
        class HttpClientHelper
        {
            /// <summary>
            /// http task state
            /// </summary>
            class TASKSTATE
            {
                public object userState;
                public HttpClient httpClient;
                public TASKSTATE(object state,HttpClient client)
                {
                    userState = state;
                    httpClient = client;
                }
            }
    
            /// <summary>
            /// 不为Null时,任意http请求完成、取消、失败时回调
            /// </summary>
            Action<Task, object> _callbackOnAnyTaskComplited;
            /// <summary>
            /// 并发控制信号
            /// </summary>
            SemaphoreSlim _semaphore;
            /// <summary>
            /// 工作标记
            /// </summary>
            bool _isWorking;
            /// <summary>
            /// 共用httpclient。为Null时,为每个http请求new httpclient。
            /// </summary>
            HttpClient _httpClient;
            /// <summary>
            /// http request task 记录
            /// </summary>
            readonly ConcurrentDictionary<Task, TASKSTATE> _workingTasks = new ConcurrentDictionary<Task, TASKSTATE>();
            /// <summary>
            /// 启动的task计数。
            /// </summary>
            long _workingCount;//原子操作
            /// <summary>
            /// 任务取消标记
            /// </summary>
            CancellationTokenSource _cancelSource;
            /// <summary>
            /// 工作器监视线程
            /// </summary>
            Task _worker;
            /// <summary>
            /// 禁止自动启动任务
            /// </summary>
            bool _autoStartWorking = true;
            /// <summary>
            /// Http Request最大并发数
            /// </summary>
            public int MaxConcurrencyLevel { get; }
            /// <summary>
            /// Http Request超时设置,毫秒。小于等于0时,使用默认值。
            /// </summary>
            public int TimeoutMillisecond { get; }
    
    
            /// <summary>
            /// 可控制并发数的HttpClient
            /// </summary>
            /// <param name="concurrencyLevel">Http Request最大并发数</param>
            /// <param name="callbackOnAnyTaskComplited">不为Null时,任意http请求完成、取消、失败时回调。注意:如果使用,请保证方法的线程安全。</param>
            /// <param name="timeoutMillisecond">Http Request超时设置,毫秒。小于等于0时,使用默认值。</param>
            /// <param name="httpClient">留空则每个任务使用一个新的HttpClient对象</param>
            public HttpClientHelper(int concurrencyLevel, Action<Task, object> callbackOnAnyTaskComplited = null, int timeoutMillisecond = 0, HttpClient httpClient = null)
            {
                if (concurrencyLevel < 1)
                {
                    throw new ArgumentOutOfRangeException("concurrencyLevel < 1");
                }
                MaxConcurrencyLevel = concurrencyLevel;
                _callbackOnAnyTaskComplited = callbackOnAnyTaskComplited;
                TimeoutMillisecond = timeoutMillisecond;
                _httpClient = httpClient;
            }
    
            /// <summary>
            /// 返回已发出的http请求数
            /// </summary>
            /// <returns></returns>
            public int GetWorkingTasksCount()
            {
                return _workingTasks.Count;
            }
    
            //public KeyValuePair<Task, object>[] GetTasks()
            //{
            //    return _workingTasks.ToArray();
            //}
    
            /// <summary>
            /// 停止工作器
            /// </summary>
            /// <param name="cancelPendingRequests">取消已发起的所有http请求</param>
            public void Stop(bool cancelPendingRequests = false)
            {
                _autoStartWorking = false;
                notifyEndWorker();
                _cancelSource.Cancel();
                if (_httpClient != null)
                {
                    _httpClient.CancelPendingRequests();
                }
                else
                {
                    foreach (var item in _workingTasks)
                    {
                        if (item.Value.httpClient != null)
                        {
                            item.Value.httpClient.CancelPendingRequests();
                        }
                    }
                }
                _workingTasks.Clear();
            }
    
            /// <summary>
            /// 重新启动工作器。stop之后使用。
            /// </summary>
            public void ReStart()
            {
                _autoStartWorking = true;
            }
    
            /// <summary>
            /// 阻塞直到所有http任务完成。
            /// </summary>
            public void WaitWorkComplited()
            {
                if (_worker != null)
                {
                    _worker.Wait();
                }
            }
    
            /// <summary>
            /// 通过 http client 获取 string。超过并发数时会阻塞,直到有http request完成。
            /// </summary>
            /// <param name="address">http url string</param>
            /// <param name="state">用户状态。用于callbackOnAnyTaskComplited回调。</param>
            /// <returns></returns>
            public Task<string> GetString(string address, object state = null)
            {
                Interlocked.Increment(ref _workingCount);
    
                notifyStartWorker();
    
                if (!_isWorking)
                {
                    Interlocked.Decrement(ref _workingCount);
                    return null;
                }
    
                _semaphore.Wait(_cancelSource.Token);
                TASKSTATE tstate = new TASKSTATE(state, null);
                HttpClient client;
                try
                {
                    if (_httpClient != null)
                    {
                        client = _httpClient;
                    }
                    else
                    {
                        client = new HttpClient();
                        if (TimeoutMillisecond > 0)
                        {
                            client.Timeout = TimeSpan.FromMilliseconds(TimeoutMillisecond);
                        }
                        tstate.httpClient = client;
                    }
                    var t = client.GetStringAsync(address);
                    _workingTasks[t] = tstate;
                    t.ContinueWith(anyTaskComplited, 
                        _cancelSource.Token,
                        TaskContinuationOptions.OnlyOnRanToCompletion & TaskContinuationOptions.NotOnRanToCompletion,
                        TaskScheduler.Current);
                    return t;
                }
                catch (HttpRequestException e)
                {
                    Interlocked.Decrement(ref _workingCount);
                    _semaphore.Release();
                    throw new HttpRequestException(e.Message, e.InnerException);
                }
            }
    
            /// <summary>
            /// 任意http task完成时回调
            /// </summary>
            /// <param name="task"></param>
            private void anyTaskComplited(Task task)
            {
                TASKSTATE tstate;
                _workingTasks.TryRemove(task, out tstate);
                //Debug.Assert(tstate.userState == state);
    
                _callbackOnAnyTaskComplited?.Invoke(task, tstate.userState);
                _semaphore.Release();
    
                Interlocked.Decrement(ref _workingCount);
            }
    
            /// <summary>
            /// 工作器初始化
            /// </summary>
            private void notifyStartWorker()
            {
                if (_isWorking) return;
    
                if (!_autoStartWorking) return;
    
                //初始化
                _isWorking = true;
                Debug.WriteLine("httpClientWorker启动……");
                _semaphore = new SemaphoreSlim(MaxConcurrencyLevel, MaxConcurrencyLevel);
                _cancelSource = new CancellationTokenSource();
                //_workingCount = 0;
    
                if (_httpClient != null && TimeoutMillisecond > 0)
                {
                    _httpClient.Timeout = TimeSpan.FromMilliseconds(TimeoutMillisecond);
                }
    
                _worker = Task.Run(new Action(workerMonitor), _cancelSource.Token);
    
                _worker.ContinueWith(a=>{ notifyEndWorker(); },TaskContinuationOptions.NotOnRanToCompletion & TaskContinuationOptions.OnlyOnRanToCompletion);
            }
    
            /// <summary>
            /// 工作器结束清理工作
            /// </summary>
            private void notifyEndWorker()
            {
                if (_isWorking)
                {
                    _isWorking = false;
                    Debug.WriteLine("httpClientWorker结束……");
                }
            }
    
            /// <summary>
            /// 任务工作器监视器
            /// </summary>
            private void workerMonitor()
            {
                do
                {
                    Thread.Sleep(1000);
                } while (_workingTasks.Count > 0 || Interlocked.Read(ref _workingCount) > 0);
            }
    
        }
    }
  • 相关阅读:
    Android Push Notification实现信息推送使用
    java动态编译
    Directx11教程(56) 建立一个skydome
    Directx11教程(51) 简单的billboard
    Directx11教程(52) 实例(instancing)的简单应用
    Directx11教程(50) 输出depth/stencil buffer的内容
    Directx11教程(54) 简单的基于GS的billboard实现
    Directx11教程(57) 环境映射
    Directx11教程(59) tessellation学习(1)
    Directx11教程(20) 一个简单的水面
  • 原文地址:https://www.cnblogs.com/bushuosx/p/7413175.html
Copyright © 2020-2023  润新知