最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

ASP.NET Core 3.x 并發(fā)限制的實(shí)現(xiàn)代碼

 更新時(shí)間:2019年11月13日 11:39:58   作者:馮輝  
這篇文章主要介紹了ASP.NET Core 3.x 并發(fā)限制的實(shí)現(xiàn)代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

前言

Microsoft.AspNetCore.ConcurrencyLimiter AspNetCore3.0后增加的,用于傳入的請(qǐng)求進(jìn)行排隊(duì)處理,避免線程池的不足.
我們?nèi)粘i_發(fā)中可能常做的給某web服務(wù)器配置連接數(shù)以及,請(qǐng)求隊(duì)列大小,那么今天我們看看如何在通過(guò)中間件形式實(shí)現(xiàn)一個(gè)并發(fā)量以及隊(duì)列長(zhǎng)度限制.

Queue策略

添加Nuget

Install-Package Microsoft.AspNetCore.ConcurrencyLimiter

    public void ConfigureServices(IServiceCollection services)
    {
      services.AddQueuePolicy(options =>
      {
        //最大并發(fā)請(qǐng)求數(shù)
        options.MaxConcurrentRequests = 2;
        //請(qǐng)求隊(duì)列長(zhǎng)度限制
        options.RequestQueueLimit = 1;
      });
      services.AddControllers();
    }
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
      //添加并發(fā)限制中間件
      app.UseConcurrencyLimiter();
      app.Run(async context =>
      {
        Task.Delay(100).Wait(); // 100ms sync-over-async

        await context.Response.WriteAsync("Hello World!");
      });
      if (env.IsDevelopment())
      {
        app.UseDeveloperExceptionPage();
      }

      app.UseHttpsRedirection();

      app.UseRouting();

      app.UseAuthorization();

      app.UseEndpoints(endpoints =>
      {
        endpoints.MapControllers();
      });
    }   

通過(guò)上面簡(jiǎn)單的配置,我們就可以將他引入到我們的代碼中,從而做并發(fā)量限制,以及隊(duì)列的長(zhǎng)度;那么問(wèn)題來(lái)了,他是怎么實(shí)現(xiàn)的呢?

 public static IServiceCollection AddQueuePolicy(this IServiceCollection services, Action<QueuePolicyOptions> configure)
{
    services.Configure(configure);
    services.AddSingleton<IQueuePolicy, QueuePolicy>();
    return services;
}

QueuePolicy采用的是SemaphoreSlim信號(hào)量設(shè)計(jì),SemaphoreSlim、Semaphore(信號(hào)量)支持并發(fā)多線程進(jìn)入被保護(hù)代碼,對(duì)象在初始化時(shí)會(huì)指定 最大任務(wù)數(shù)量,當(dāng)線程請(qǐng)求訪問(wèn)資源,信號(hào)量遞減,而當(dāng)他們釋放時(shí),信號(hào)量計(jì)數(shù)又遞增。

   /// <summary>
    ///   構(gòu)造方法(初始化Queue策略)
    /// </summary>
    /// <param name="options"></param>
    public QueuePolicy(IOptions<QueuePolicyOptions> options)
    {
      _maxConcurrentRequests = options.Value.MaxConcurrentRequests;
      if (_maxConcurrentRequests <= 0)
      {
        throw new ArgumentException(nameof(_maxConcurrentRequests), "MaxConcurrentRequests must be a positive integer.");
      }

      _requestQueueLimit = options.Value.RequestQueueLimit;
      if (_requestQueueLimit < 0)
      {
        throw new ArgumentException(nameof(_requestQueueLimit), "The RequestQueueLimit cannot be a negative number.");
      }
      //使用SemaphoreSlim來(lái)限制任務(wù)最大個(gè)數(shù)
      _serverSemaphore = new SemaphoreSlim(_maxConcurrentRequests);
    }

ConcurrencyLimiterMiddleware中間件

    /// <summary>
    /// Invokes the logic of the middleware.
    /// </summary>
    /// <param name="context">The <see cref="HttpContext"/>.</param>
    /// <returns>A <see cref="Task"/> that completes when the request leaves.</returns>
    public async Task Invoke(HttpContext context)
    {
      var waitInQueueTask = _queuePolicy.TryEnterAsync();

      // Make sure we only ever call GetResult once on the TryEnterAsync ValueTask b/c it resets.
      bool result;

      if (waitInQueueTask.IsCompleted)
      {
        ConcurrencyLimiterEventSource.Log.QueueSkipped();
        result = waitInQueueTask.Result;
      }
      else
      {
        using (ConcurrencyLimiterEventSource.Log.QueueTimer())
        {
          result = await waitInQueueTask;
        }
      }

      if (result)
      {
        try
        {
          await _next(context);
        }
        finally
        {
          _queuePolicy.OnExit();
        }
      }
      else
      {
        ConcurrencyLimiterEventSource.Log.RequestRejected();
        ConcurrencyLimiterLog.RequestRejectedQueueFull(_logger);
        context.Response.StatusCode = StatusCodes.Status503ServiceUnavailable;
        await _onRejected(context);
      }
    }

每次當(dāng)我們請(qǐng)求的時(shí)候首先會(huì)調(diào)用_queuePolicy.TryEnterAsync(),進(jìn)入該方法后先開啟一個(gè)私有l(wèi)ock鎖,再接著判斷總請(qǐng)求量是否≥(請(qǐng)求隊(duì)列限制的大小+最大并發(fā)請(qǐng)求數(shù)),如果當(dāng)前數(shù)量超出了,那么我直接拋出,送你個(gè)503狀態(tài);

 if (result)
 {
     try
     {
       await _next(context);
     }
     finally
    {
      _queuePolicy.OnExit();
    }
    }
    else
    {
      ConcurrencyLimiterEventSource.Log.RequestRejected();
      ConcurrencyLimiterLog.RequestRejectedQueueFull(_logger);
      context.Response.StatusCode = StatusCodes.Status503ServiceUnavailable;
      await _onRejected(context);
    }

問(wèn)題來(lái)了,我這邊如果說(shuō)還沒(méi)到你設(shè)置的大小呢,我這個(gè)請(qǐng)求沒(méi)有給你服務(wù)器造不成壓力,那么你給我處理一下吧.

await _serverSemaphore.WaitAsync();異步等待進(jìn)入信號(hào)量,如果沒(méi)有線程被授予對(duì)信號(hào)量的訪問(wèn)權(quán)限,則進(jìn)入執(zhí)行保護(hù)代碼;否則此線程將在此處等待,直到信號(hào)量被釋放為止

 lock (_totalRequestsLock)
  {
    if (TotalRequests >= _requestQueueLimit + _maxConcurrentRequests)
    {
       return false;
    }
      TotalRequests++;
    }
    //異步等待進(jìn)入信號(hào)量,如果沒(méi)有線程被授予對(duì)信號(hào)量的訪問(wèn)權(quán)限,則進(jìn)入執(zhí)行保護(hù)代碼;否則此線程將在此處等待,直到信號(hào)量被釋放為止
    await _serverSemaphore.WaitAsync();
    return true;
  }

返回成功后那么中間件這邊再進(jìn)行處理,_queuePolicy.OnExit();通過(guò)該調(diào)用進(jìn)行調(diào)用_serverSemaphore.Release();釋放信號(hào)燈,再對(duì)總請(qǐng)求數(shù)遞減

Stack策略

再來(lái)看看另一種方法,棧策略,他是怎么做的呢?一起來(lái)看看.再附加上如何使用的代碼.

   public void ConfigureServices(IServiceCollection services)
    {
      services.AddStackPolicy(options =>
      {
        //最大并發(fā)請(qǐng)求數(shù)
        options.MaxConcurrentRequests = 2;
        //請(qǐng)求隊(duì)列長(zhǎng)度限制
        options.RequestQueueLimit = 1;
      });
      services.AddControllers();
    }

通過(guò)上面的配置,我們便可以對(duì)我們的應(yīng)用程序執(zhí)行出相應(yīng)的策略.下面再來(lái)看看他是怎么實(shí)現(xiàn)的呢

 public static IServiceCollection AddStackPolicy(this IServiceCollection services, Action<QueuePolicyOptions> configure)
    {
      services.Configure(configure);
      services.AddSingleton<IQueuePolicy, StackPolicy>();
      return services;
    }

可以看到這次是通過(guò)StackPolicy類做的策略.來(lái)一起來(lái)看看主要的方法

    /// <summary>
    ///   構(gòu)造方法(初始化參數(shù))
    /// </summary>
    /// <param name="options"></param>
    public StackPolicy(IOptions<QueuePolicyOptions> options)
    {
      //棧分配
      _buffer = new List<ResettableBooleanCompletionSource>();
      //隊(duì)列大小
      _maxQueueCapacity = options.Value.RequestQueueLimit;
      //最大并發(fā)請(qǐng)求數(shù)
      _maxConcurrentRequests = options.Value.MaxConcurrentRequests;
      //剩余可用空間
      _freeServerSpots = options.Value.MaxConcurrentRequests;
    }

當(dāng)我們通過(guò)中間件請(qǐng)求調(diào)用,_queuePolicy.TryEnterAsync()時(shí),首先會(huì)判斷我們是否還有訪問(wèn)請(qǐng)求次數(shù),如果_freeServerSpots>0,那么則直接給我們返回true,讓中間件直接去執(zhí)行下一步,如果當(dāng)前隊(duì)列=我們?cè)O(shè)置的隊(duì)列大小的話,那我們需要取消先前請(qǐng)求;每次取消都是先取消之前的保留后面的請(qǐng)求;

  public ValueTask<bool> TryEnterAsync()
    {
      lock (_bufferLock)
      {
        if (_freeServerSpots > 0)
        {
          _freeServerSpots--;
          return _trueTask;
        }
        // 如果隊(duì)列滿了,取消先前的請(qǐng)求
        if (_queueLength == _maxQueueCapacity)
        {
          _hasReachedCapacity = true;
          _buffer[_head].Complete(false);
          _queueLength--;
        }
        var tcs = _cachedResettableTCS ??= new ResettableBooleanCompletionSource(this);
        _cachedResettableTCS = null;
        if (_hasReachedCapacity || _queueLength < _buffer.Count)
        {
          _buffer[_head] = tcs;
        }
        else
        {
          _buffer.Add(tcs);
        }
        _queueLength++;
        // increment _head for next time
        _head++;
        if (_head == _maxQueueCapacity)
        {
          _head = 0;
        }
        return tcs.GetValueTask();
      }
    }

當(dāng)我們請(qǐng)求后調(diào)用_queuePolicy.OnExit();出棧,再將請(qǐng)求長(zhǎng)度遞減

  public void OnExit()
    {
      lock (_bufferLock)
      {
        if (_queueLength == 0)
        {
          _freeServerSpots++;

          if (_freeServerSpots > _maxConcurrentRequests)
          {
            _freeServerSpots--;
            throw new InvalidOperationException("OnExit must only be called once per successful call to TryEnterAsync");
          }

          return;
        }

        // step backwards and launch a new task
        if (_head == 0)
        {
          _head = _maxQueueCapacity - 1;
        }
        else
        {
          _head--;
        }
        //退出,出棧
        _buffer[_head].Complete(true);
        _queueLength--;
      }
    }

總結(jié)

基于棧結(jié)構(gòu)的特點(diǎn),在實(shí)際應(yīng)用中,通常只會(huì)對(duì)棧執(zhí)行以下兩種操作:

  • 向棧中添加元素,此過(guò)程被稱為"進(jìn)棧"(入?;驂簵#?;
  • 從棧中提取出指定元素,此過(guò)程被稱為"出棧"(或彈棧);

隊(duì)列存儲(chǔ)結(jié)構(gòu)的實(shí)現(xiàn)有以下兩種方式:

  • 順序隊(duì)列:在順序表的基礎(chǔ)上實(shí)現(xiàn)的隊(duì)列結(jié)構(gòu);
  • 鏈隊(duì)列:在鏈表的基礎(chǔ)上實(shí)現(xiàn)的隊(duì)列結(jié)構(gòu);

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • 解析ASP.NET?Core中Options模式的使用及其源碼

    解析ASP.NET?Core中Options模式的使用及其源碼

    這篇文章主要介紹了ASP.NET?Core中Options模式的使用及其源碼解析,在ASP.NET Core中引入了Options這一使用配置方式,其主要是為了解決依賴注入時(shí)需要傳遞指定數(shù)據(jù)問(wèn)題(不是自行獲取,而是能集中配置),需要的朋友可以參考下
    2022-03-03
  • 利用asp.net實(shí)現(xiàn)生成不重復(fù)訂單號(hào)

    利用asp.net實(shí)現(xiàn)生成不重復(fù)訂單號(hào)

    訂單號(hào)在購(gòu)物過(guò)程中起到了很好的識(shí)別作用,更方便的有利于工作人員識(shí)別商品,本文介紹利用asp.net實(shí)現(xiàn)生成訂單號(hào)
    2012-12-12
  • ASP.NET文件處理如何操作

    ASP.NET文件處理如何操作

    這篇文章主要介紹了ASP.NET文件處理如何操作,需要的朋友可以參考下
    2015-09-09
  • ASP.NET MVC 3仿Server.Transfer效果的實(shí)現(xiàn)方法

    ASP.NET MVC 3仿Server.Transfer效果的實(shí)現(xiàn)方法

    這篇文章主要介紹了ASP.NET MVC 3仿Server.Transfer效果的實(shí)現(xiàn)方法,需要的朋友可以參考下
    2015-10-10
  • 如何給asp.net core寫個(gè)中間件記錄接口耗時(shí)

    如何給asp.net core寫個(gè)中間件記錄接口耗時(shí)

    這篇文章主要給大家介紹了關(guān)于如何給asp.net core寫個(gè)中間件記錄接口耗時(shí)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用asp.net core具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09
  • ASP.NET Core利用UrlFirewall對(duì)請(qǐng)求進(jìn)行過(guò)濾的方法示例

    ASP.NET Core利用UrlFirewall對(duì)請(qǐng)求進(jìn)行過(guò)濾的方法示例

    這篇文章主要給大家介紹了關(guān)于ASP.NET Core利用UrlFirewall對(duì)請(qǐng)求進(jìn)行過(guò)濾的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2018-05-05
  • 使用xenocode代碼混淆加密的操作步驟

    使用xenocode代碼混淆加密的操作步驟

    之前就了解過(guò)混淆加密工具xenocode,下面記錄一下xenocode2010代碼混淆的操作步驟,大家參考使用吧
    2014-01-01
  • asp.net 2.0多語(yǔ)言網(wǎng)站解決方法

    asp.net 2.0多語(yǔ)言網(wǎng)站解決方法

    asp.net 2.0中的App_GlobalResources可以用來(lái)解決本地化的問(wèn)題,程序會(huì)根據(jù)瀏覽器的語(yǔ)言首選項(xiàng)自動(dòng)判斷顯示出本地化的界面。
    2008-09-09
  • .NET使用QuestPDF高效地生成PDF文檔

    .NET使用QuestPDF高效地生成PDF文檔

    在.NET平臺(tái)中操作生成PDF的類庫(kù)有很多如常見的有iTextSharp、PDFsharp、Aspose.PDF等,本文主要介紹的是如何使用QuestPDF實(shí)現(xiàn)發(fā)票PDF文檔生成功能,需要的可以了解下
    2024-01-01
  • ASP.NET操作EXCEL的總結(jié)篇

    ASP.NET操作EXCEL的總結(jié)篇

    今年有個(gè)系統(tǒng)的部分EXCEL的操作也讓我做,順便結(jié)合之前操作EXCEL的經(jīng)驗(yàn)作一下總結(jié),可能也算不上什么,對(duì)于絕大多數(shù)來(lái)說(shuō)也沒(méi)什么技術(shù)含量,網(wǎng)上一搜一大把,但我想還是有必要總結(jié)一下
    2011-02-02

最新評(píng)論

噶尔县| 吴桥县| 镇原县| 宁化县| 成武县| 南京市| 日照市| 公主岭市| 沈丘县| 汾西县| 阳山县| 大石桥市| 塔河县| 汝阳县| 故城县| 江都市| 拉孜县| 武山县| 宁夏| 贵港市| 天气| 张家口市| 崇礼县| 曲阳县| 阜宁县| 洪洞县| 府谷县| 永宁县| 海晏县| 双柏县| 罗定市| 正定县| 余庆县| 平和县| 吴旗县| 兴义市| 尉氏县| 前郭尔| 星子县| 焦作市| 平泉县|