首页 > 编程语言 >.net C# 流量限制令牌桶算法工具类

.net C# 流量限制令牌桶算法工具类

时间:2023-10-09 17:57:11浏览次数:55  
标签:cancellationToken 令牌 C# tokensPerSecond int stopwatch net bucketSize

流量限制令牌桶算法工具类

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;

namespace Common
{
    /// <summary>
    /// 令牌桶算法工具类
    /// </summary>
    public class TokenBucket
    {
        /// <summary>
        /// 令牌桶队列
        /// </summary>
        private readonly Queue<int> _tokens = new Queue<int>();

        /// <summary>
        /// 令牌桶容量(最大令牌数)
        /// </summary>
        private readonly int _bucketSize;

        /// <summary>
        /// 初始化令牌桶集合间隔(秒)
        /// </summary>
        public int BucketSize => _bucketSize;

        /// <summary>
        /// 初始化令牌桶集合间隔(秒)
        /// </summary>
        private readonly int _tokensPerSecond;

        /// <summary>
        /// 时间间隔监听器
        /// </summary>
        private readonly Stopwatch _stopwatch = new Stopwatch();

        /// <summary>
        /// 令牌桶
        /// </summary>
        /// <param name="bucketSize">令牌桶容量(默认:512KB)</param>
        /// <param name="tokensPerSecond">初始化令牌桶集合间隔(默认:1秒)</param>
        public TokenBucket(int bucketSize = 512 * 1024, int tokensPerSecond = 1)
        {
            _bucketSize = bucketSize;
            _tokensPerSecond = tokensPerSecond;
        }

        /// <summary>
        /// 请求口令
        /// </summary>
        /// <param name="count">请求分配令牌个数</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>已分配口令个数</returns>
        public async Task<int> GetToken(int count, CancellationToken cancellationToken = default)
        {
            //启动监听
            if (!_stopwatch.IsRunning)
            {
                _stopwatch.Start();
            }
            //重新监听
            else if (_stopwatch.ElapsedMilliseconds >= _tokensPerSecond * 1000)
            {
                _stopwatch.Reset();
            }

            //初始化令牌桶
            while (_tokens.Count < _bucketSize && _stopwatch.ElapsedMilliseconds < _tokensPerSecond * 1000)
            {
                _tokens.Enqueue(1);
            }

            if (_tokens.Count > 0)
            {
                //分配口令
                for (int i = 0; i < count; i++)
                {
                    //如果无可用口令,等待下一轮初始化口令
                    if (_tokens.Count == 0)
                    {
                        _stopwatch.Stop();
                        await Task.Delay(_tokensPerSecond * 1000 - (int)_stopwatch.ElapsedMilliseconds, cancellationToken);

                        //返回已分配口令个数
                        return i;
                    }
                    _tokens.Dequeue();
                }

                return count;
            }
            else
            {
                return 0;
            }
        }

        /// <summary>
        /// 使用令牌
        /// </summary>
        /// <param name="count">使用的令牌数,如果大于最大容量,则循环分配令牌</param>
        /// <param name="func">令牌分配委托,参数1:待分配索引,参数2:已分配口令个数</param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task UseToken(int count, Func<int, int, Task> func, CancellationToken cancellationToken = default)
        {
            int i = 0;
            int t = count;

            while (t > 0)
            {
                int j;
                if ((j = await GetToken(t, cancellationToken)) > 0)
                {
                    await func(i, j);

                    t -= j;
                    i += j;
                }
            }
        }
    }
}

  用法:

await tokenBucket.UseToken(buffer.Length, new Func<int, int, Task>(async (i, j) =>
{
    await wirteStream.WriteAsync(bytes.Slice(i, j), cancellationToken);
}), cancellationToken);

  

标签:cancellationToken,令牌,C#,tokensPerSecond,int,stopwatch,net,bucketSize
From: https://www.cnblogs.com/HelloCreator/p/17752553.html

相关文章

  • php之Cookies和Sessions
    PHPCookies1.什么是Cookie?cookie常用于识别用户cookie是服务器留在用户计算机中的小文件。每当相同的计算机通过浏览器请求页面时,它同时会发送cookie。通过PHP,您能够创建并取回cookie的值2.如何创建cookie?setcookie()函数用于设置cookie。setcookie()函数......
  • k8s中,如何通过kubeconfig实现权限的隔离、用户的隔离?
    1、需求及背景说明 在k8s环境,如果想要实现不同的用户,可以有操作不同的命名空间的权限,对命名空间中的不同的对象有不同的操作的权限,该如何实现呢? 有什么样的使用的场景呢? 简单来说,虽然都是通过kubectl来对k8s集群进行管理的操作,但是不同的人员,通过不同的kube-config,就可......
  • Codeforces Round 726 (Div. 2) B. Bad Boy
    给一个\(n\timesm\)的平面,一个初始位置\((i,j)\)。需要放两个废弃物在平面上,位置为\((x_1,y_1),(x_2,y_2)\)。使得从\((i,j)\)出发,捡起两个废弃物后,回到原位置,所经过的曼哈顿距离最长。询问一组合法的\((x_1,y_1),(x_2,y_2)\)。性质:二维平面上有关的曼哈......
  • CF1878G wxhtzdy ORO Tree
    CF1878GwxhtzdyOROTree设\(f(x,y)\)表示树上\(x\)到\(y\)简单路径上的点权或和中\(1\)的个数。有一个性质:选取的\(z\)节点一定满足它比它左边的点(\(l\))或者右边的点(\(r\))的贡献至少要多一位,即\(f(x,l)<f(x,z)\)或\(f(y,r)<f(y,z)\),有了这个性质,问题就简单很多......
  • Oracle和达梦:连接多行查询结果
    Oracle和达梦:LISTAGG连接查询结果LISTAGG介绍使用LISTAGG函数,您可以将多行数据连接成一个字符串,并指定分隔符进行分隔。这在需要将多行数据合并为单个字符串的情况下非常有用,例如将多个值合并为逗号分隔的列表。函数介绍LISTAGG(column,delimiter)WITHINGROUP(ORDER......
  • Office三件套小技巧
    当谈到Office三件套(Word、Excel和PowerPoint)的小技巧时,以下是非常详细的内容,确保不错过任何小知识点。让我们逐个介绍:MicrosoftWord小技巧:快速格式化文本:使用Ctrl+B、Ctrl+I和Ctrl+U分别快速添加粗体、斜体和下划线格式。创建自定义标签页:在"文件"菜单中选择"选项",......
  • tomcat部署多个站点
    只要在tomcat的server.xml中增加一个service节点,新建一个webapps2文件夹,把新站点的文件放到这个文件中的ROOT目录下即可<Servicename="Catalina"><Connectorport="8088"protocol="HTTP/1.1"connectionTimeout="20000"......
  • CPU飙升怎么办?解决定位问题的思路
     https://mp.weixin.qq.com/s/J_O5380MR06bYFJadxJRLw01线上服务器CPU飙升,如何定位到Java代码解决这个问题的关键是要找到Java代码的位置。下面分享一下排查思路,以CentOS为例,总结为4步。第1步,使用top命令找到占用CPU高的进程。第2步,使用ps–mp命令找到进程下占用CPU高的线......
  • Oracle和达梦:相似度函数:UTL
    Oracle和达梦的:相似度函数:UTL函数:UTL_MATCH.edit_distance_similarityUTL_MATCH.edit_distance_similarity是Oracle数据库中的一个函数,用于计算两个字符串之间的相似度。它基于编辑距离算法,该算法用于衡量两个字符串之间的相似程度。编辑距离是通过计算将一个字符串转换为......
  • Rust cargo常用命令
    目录设置国内镜像创建新项目构建项目运行项目检查项目,但不构建可执行文件运行项目的测试发布项目更新依赖查看项目依赖关系树创建新的库项目文档生成设置国内镜像cd~/.cargo#创建config文件vimconfig#添加如下镜像源[source.crates-io]registry="https://github.com/......