国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

兩種基于時間窗口的限流器的簡單實現

開發 前端
在實現的TryAcquire方法中,我們先確定當前時間是否超過了設定的“下一個窗口開始時間”,如果是則調用Interlocked.CompareExchange方法修改__nextWindowStartTimeTicks字段。

之前開發的一款基于OpenTelemetry的Tracing組件需要使用基于速率限制(Rate Limiting)的跟蹤采樣策略,本想使用現有的解決方案,比如System.Threading.RateLimiting命名空間下的RateLimiter。大體看了RateLimiter的三種實現(固定窗口、滑動窗口和令牌桶),覺得過于相對復雜了點,代碼還涉及到鎖,而且提供的功能我也不太需要,于是嘗試實現一種簡單且無鎖解決方案。

一、滑動時間窗口

我為RateLimiter定義了如下這個簡單的IRateLimiter接口,唯一的無參方法TryAcquire利用返回的布爾值確定當前是否超出設定的速率限制。我只提供的兩種基于時間窗口的實現,如下所示的基于“滑動時間窗口”的實現類型SliddingWindowRateLimiter,我們在構造的時候指定時間窗口和閾值。SliddingWindowRateLimiter采用一種“討巧”的實現,它直接利用了BoundedChannel<DateTimeOffset>對象,我們將指定的閾值作為它的最大容量。

public interface IRateLimiter
{
    bool TryAcquire();
}

public sealed class SliddingWindowRateLimiter: IRateLimiter
{
    private readonly TimeSpan _window;
    private readonly ChannelReader<DateTimeOffset> _reader;
    private readonly ChannelWriter<DateTimeOffset> _writer;
    public SliddingWindowRateLimiter(TimeSpan window, int permit)
    {
        _window = window;
        var options = new BoundedChannelOptions (permit)
        {
            FullMode = BoundedChannelFullMode.Wait,
            SingleReader = false,
            SingleWriter = true
        };
        var channel = Channel
            .CreateBounded<DateTimeOffset>(options);
        _reader = channel.Reader;
        _writer = channel.Writer;
        Task.Factory.StartNew(
            Trim,TaskCreationOptions.LongRunning);
    }

    public bool TryAcquire() 
    => _writer.TryWrite(DateTimeOffset.UtcNow);
    private void Trim()
    {
        if (!_reader.TryPeek(out var timestamp))
        {
            Task.Delay(_window).Wait();
            Trim();
        }
        else
        {
            var delay = _window 
                - (DateTimeOffset.UtcNow - timestamp);
            if (delay > TimeSpan.Zero)
            {
                Task.Delay(delay).Wait();
                Trim();
            }
            else
            {
                var valueTask = _reader.ReadAsync();
                if (!valueTask.IsCompleted) 
                    _ = valueTask.Result;
                Trim();
            }
        }
    }
}

在實現的TryAcquire方法中,我們試著將當前時間戳寫入這個Channel,并將寫入的結果(成功或者失敗)作為返回值。為了讓Channel中只包含指定時間窗口的時間戳,我們利用一個LongRuning的Task執行Trim方法對過期的時間戳進行“裁剪”。Trim會調用ChannelReader的TRyPeek方法,如果返回False,意味著Channel為空,此時會等待一段窗口時間再進行“裁剪”。如果提取出來時間戳在Now-Window與當前時間之間,意味著Channel里面的時間戳均在設定的窗口內,此時同樣需要等待,等待時間為Window - (Now - Timestamp);只有在提取的時間超出窗口范圍,我們才需要將其從Channel中移除。

var limiter = new SliddingWindowRateLimiter(
    TimeSpan.FromSeconds(2),2);

var index = 0;
await Task.WhenAll( Enumerable.Range(1, 100)
    .Select(_ => Task.Run(() => {
        while (true)
        {
            if (limiter.TryAcquire())
            {
                Console.WriteLine(
                    $"[{DateTimeOffset.Now}]{Interlocked.Increment(ref index)}");
            } 
        }
    })));

我們在上面的演示程序中使用這個SliddingWindowRateLimiter,設定的限速規則為 2/2s。我們創建了100個Task并發地調用這個SliddingWindowRateLimiter,并將它返回True時的時間戳顯示出來,具體輸出如下所示。

圖片圖片

二、固定時間窗口

如下這個FixedWindowRateLimiter類型是針對“固定窗口”的實現,字段_windowTicks和_permit同樣表示時間窗口的時長(這里我們使用Int64類型的Ticks屬性)和閾值。_nextWindowStartTimeTicks表示下一次固定窗口的起始時間,這個需要動態調整,為了確保只有一個線程能夠修改它,我們定義了_windowReseting這個“信號量”。_count是一個計數器,我們使用它確定是否“超速”。

public sealed class FixedWindowRateLimiter : IRateLimiter
{
    private readonly long _windowTicks;
    private readonly int _permit;
    private long _nextWindowStartTimeTicks;
    private volatile int _count = 0;

    public FixedWindowRateLimiter(TimeSpan window, int permit)
    {
        _windowTicks = window.Ticks;
        _permit = permit;
        _nextWindowStartTimeTicks 
            = DateTimeOffset.UtcNow.Add(window).Ticks;
    }

    public bool TryAcquire()
    {
        // 超出時間窗口,重置計數器,并調整下一個時間窗口的開始時間
        var now = DateTimeOffset.UtcNow.Ticks;
        var nextWindowStartTimeTicks = nextWindowStartTimeTicks;
        if (now >= nextWindowStartTimeTicks 
            && Interlocked.CompareExchange(
            ref _nextWindowStartTimeTicks
            , now + _windowTicks, nextWindowStartTimeTicks) 
            == nextWindowStartTimeTicks)
        {
            Interlocked.Exchange(ref _count, 1);
            return true;
        }
        return _count < _permit 
            && Interlocked.Increment(ref _count) <= _permit;
    }
}

在實現的TryAcquire方法中,我們先確定當前時間是否超過了設定的“下一個窗口開始時間”,如果是則調用Interlocked.CompareExchange方法修改__nextWindowStartTimeTicks字段。成功修改__nextWindowStartTimeTicks的線程會調整窗口開始時間,并重置計數器_count為1,并返回True。如果計數器大于等于設定閾值,方法返回False。否則我們讓計數器+1,如果該值<=閾值,返回True,否則返回False。

IRateLimiter limiter = new FixedWindowRateLimiter(
    window: TimeSpan.FromSeconds(2), permit: 2);

var index = 0;
await Task.WhenAll( Enumerable.Range(1, 100)
    .Select(_ => Task.Run(() => {
        while (true)
        {
            if (limiter.TryAcquire())
            {
                Console.WriteLine(
                    $"[{DateTimeOffset.Now}]{Interlocked.Increment(ref index)}");
            }       
        }
    })));

將FixedWindowRateLimiter應用到上面的演示程序,依然能得到我們希望的輸出結果。

圖片 圖片

責任編輯:武曉燕 來源: 大內老A
相關推薦

2023-07-10 07:58:45

2009-06-15 15:02:48

Spring定時器

2010-08-11 14:22:26

Flex彈出窗口

2025-01-26 00:00:25

限流組件HTTP

2022-02-21 08:18:38

option編程模式

2012-10-16 09:40:38

洗牌算法

2010-07-14 10:30:26

Perl多線程

2010-10-14 14:33:15

MySQL多表聯查

2021-12-08 10:47:35

RabbitMQ 實現延遲

2010-08-13 12:54:20

Flex彈出窗口

2010-09-07 09:18:16

DIV彈出窗口

2010-05-28 09:49:48

MySQL遠程連接

2012-11-29 10:45:31

2010-11-25 10:21:20

MySql查詢時間段

2009-07-02 15:50:36

JSP體系結構

2021-05-27 10:57:01

TCP定時器網絡協議

2010-10-11 10:31:51

MySQL分區

2013-05-27 14:31:34

Hadoop 2.0

2009-09-14 19:25:09

Ruby form

2020-05-11 13:03:03

SR-TEIP路由器
點贊
收藏

51CTO技術棧公眾號

69堂精品视频| 亚洲一区久久| 91原色影院| 国内揄拍国内精品少妇国语| 久久久国产精品不卡| 日韩欧美另类中文字幕| 欧美日韩a区| 3d欧美精品动漫xxxx无尽| 久草在线在线| 免费日韩av电影| 久久久久久国产精品美女| 少妇视频一区| av一级在线| 88av.com| 国产精品视频麻豆| 青青草原在线亚洲| 中文乱码字幕高清在线观看| 91日韩在线播放| 欧美日韩国产高清一区| 免费观看成人av| 亚洲综合在线电影| 性刺激的欧美三级视频| 国产精品视频中文字幕91| 欧美亚洲丝袜传媒另类| 日韩国产高清在线| 岛国精品在线| jizz欧美大全| 大波视频国产精品久久| 欧美va在线播放| 成人精品国产福利| 欧亚精品一区| 九色视频成人自拍| www亚洲国产| 久久久久久国产精品三级玉女聊斋| 国产精品国产自产拍高清av| 综合一区av| 性xxxxfreexxxxx欧美丶| 国内自拍在线观看| 国产久一一精品| 亚洲第一综合天堂另类专| 久久久综合精品| 欧美在线黄色| www.99re.av| 欧美一级特黄a| 亚洲1卡2卡3卡4卡乱码精品| 亚洲人成电影| 色综合888| 精品视频在线导航| 亚洲欧美国产另类| 一本一本久久a久久精品综合小说 一本一本久久a久久精品牛牛影视 | 国产日产欧美精品一区二区三区| 五月天亚洲色图| 在线免费av电影| 久久久999免费视频| 久久久久亚洲精品国产| 国产91网红主播在线观看| 成人黄色在线视频| 日韩欧美伦理| 黄色漫画在线免费看| 2018av男人天堂| 日本午夜精品一区二区三区| 欧美精品日韩www.p站| 欧洲色大大久久| 97成人超碰视| 激情久久综合| 久久国产精品美女| 日本在线免费中文字幕| caoporn超碰97| 麻豆一区区三区四区产品精品蜜桃| 美女性感视频久久久| 欧美无人高清视频在线观看| 久久综合狠狠综合| 国产伦理一区| 伊甸园亚洲一区| 性欧美18~19sex高清播放| 黄污在线观看| 农民人伦一区二区三区| 99在线视频播放| 99久久99热这里只有精品 | 久久中文在线| 国产淫片在线观看| 经典三级在线| 日韩大尺度黄色| 欧美日韩三级电影在线| 99精品欧美一区| sm国产在线调教视频| 在线免费视频一区| 一区在线电影| 超碰97国产在线| 7m精品福利视频导航| 亚洲精品小视频在线观看| 欧美性猛交xxxx乱大交3| 久久免费视频色| 蜜桃精品视频在线观看| 欧美在线免费| 亚洲亚洲免费| 国产精品国产三级在线观看| 福利在线导航136| 在线视频毛片| 狠狠热免费视频| 成人小视频在线观看免费| 欧美理论一区二区| 99久久自偷自偷国产精品不卡| 欧亚精品中文字幕| 欧美精品在线看| 最近2019中文字幕一页二页| 精品国产一区a| 欧美精品丝袜中出| 精品久久久久久| 一色屋精品亚洲香蕉网站| 91美女片黄在线| 国产精品自拍一区| 蜜桃一区二区三区四区| 国产精品美女久久久| 国产精品v亚洲精品v日韩精品 | 免费欧美在线| 欧美成人综合| 国产成人无码精品久久久性色| 第一福利在线视频| 亚洲成人1区2区| 国产精品久久久久福利| 国产精品免费成人| 国产成人精选| 性生活免费在线观看| 三上悠亚一区二区| 国产福利一区二区三区视频在线| 在线观看欧美日韩| 欧美国产一区在线| 99精品在线观看视频| 国产盗摄视频一区二区三区| 麻豆国产91在线播放| 视频一区二区三区入口| 久久精品天堂| 日韩精品久久理论片| 日韩电影在线观看网站| 日韩在线一区二区| 日韩电影在线观看电影| 日韩精品乱码av一区二区| 麻豆久久精品| 日韩专区欧美专区| 麻豆成人在线观看| 国产自产视频一区二区三区| 精品一区二区三区香蕉蜜桃| 久久精品理论片| 国产真实精品久久二三区| 国产精品自拍毛片| www.色精品| 久久综合资源网| 国产亚洲成aⅴ人片在线观看 | 国产第一亚洲| 亚洲开心激情| 国产精品久久久网站| 亚洲精品进入| 国产精品毛片久久| 在线综合亚洲| 久久精品国产一区二区三 | 亚洲精品乱码| 亚洲情综合五月天| 激情小视频在线| 免费黄网站欧美| 日韩一区二区在线视频| 亚洲国产日韩欧美综合久久| 超碰97在线看| 亚洲系列另类av| 日韩女优电影在线观看| 日本激情综合网| 亚洲精品免费av| 精品乱码一区| 国产精品h视频| 欧美日韩在线中文| 人成在线视频| 日韩黄色影院| 影视一区二区三区| 国产精品毛片视频| 亚洲精品888| 日本亚洲天堂网| 久久综合久色欧美综合狠狠| 国产精品成人免费精品自在线观看| 亚洲精品国产第一综合99久久| 精品久久久香蕉免费精品视频| 欧美疯狂做受xxxx富婆| 国产一区二区三区丝袜| 97色伦亚洲国产| 国产伦精品一区二区三区四区免费 | 国产精品色视频| 欧美日韩在线高清| 日韩av综合在线观看| 黄页网址在线观看| 亚洲91av| 一区二区精彩视频| 欧美黄免费看| 丁香一区二区三区| 亚洲在线视频免费观看| 日韩欧美的一区二区| 欧美激情亚洲另类| 99热99热| 777久久久精品一区二区三区| 日本五码在线| av在线不卡精品| 亚洲二区三区不卡|