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

C#使用SemaphoreSlim實(shí)現(xiàn)并發(fā)控制與限流策略的實(shí)戰(zhàn)指南

 更新時(shí)間:2025年11月12日 09:05:24   作者:拾荒的小海螺  
在現(xiàn)代應(yīng)用中(如爬蟲、并發(fā)請(qǐng)求、數(shù)據(jù)庫(kù)連接池、異步任務(wù)處理),我們常常需要限制同時(shí)執(zhí)行的任務(wù)數(shù)量,以避免過(guò)載或資源競(jìng)爭(zhēng),在 C# 中,最簡(jiǎn)潔高效的解決方案之一就是SemaphoreSlim,本文就給大家介紹了C#使用SemaphoreSlim實(shí)現(xiàn)并發(fā)控制與限流策略的實(shí)戰(zhàn)指南

1、簡(jiǎn)述

在現(xiàn)代應(yīng)用中(如爬蟲、并發(fā)請(qǐng)求、數(shù)據(jù)庫(kù)連接池、異步任務(wù)處理),我們常常需要限制同時(shí)執(zhí)行的任務(wù)數(shù)量,以避免過(guò)載或資源競(jìng)爭(zhēng)。

在 C# 中,最簡(jiǎn)潔高效的解決方案之一就是 —— SemaphoreSlim。

2、基本原理

SemaphoreSlim 內(nèi)部維護(hù)一個(gè)“許可計(jì)數(shù)(Permit Count)”。
每個(gè)線程執(zhí)行前需要調(diào)用 Wait()(或 WaitAsync())來(lái)獲取許可,執(zhí)行結(jié)束后調(diào)用 Release() 歸還許可。

當(dāng)所有許可被占用時(shí),新線程會(huì)等待,直到有資源釋放。SemaphoreSemaphoreSlim 都用于控制并發(fā)訪問(wèn),但它們的實(shí)現(xiàn)和性能不同。

對(duì)比項(xiàng)SemaphoreSemaphoreSlim
實(shí)現(xiàn)方式內(nèi)核對(duì)象(較重)用戶態(tài)輕量實(shí)現(xiàn)(高性能)
是否跨進(jìn)程? 是? 否
是否支持 async/await? 否? 是
推薦場(chǎng)景跨進(jìn)程同步應(yīng)用內(nèi)并發(fā)控制

結(jié)論: 在現(xiàn)代 C# 應(yīng)用中(如 Web API、后臺(tái)任務(wù)、異步 I/O),使用 SemaphoreSlim 是首選。

3、實(shí)踐樣例

3.1 基本用法

using System;
using System.Threading;
using System.Threading.Tasks;

class Program
{
    static SemaphoreSlim semaphore = new SemaphoreSlim(3); // 最多3個(gè)并發(fā)

    static async Task Main()
    {
        var tasks = new Task[10];
        for (int i = 0; i < 10; i++)
        {
            int id = i;
            tasks[i] = Task.Run(() => DoWorkAsync(id));
        }

        await Task.WhenAll(tasks);
        Console.WriteLine("全部任務(wù)完成!");
    }

    static async Task DoWorkAsync(int id)
    {
        await semaphore.WaitAsync(); // 獲取許可
        try
        {
            Console.WriteLine($"任務(wù) {id} 開(kāi)始,當(dāng)前時(shí)間:{DateTime.Now:T}");
            await Task.Delay(1000); // 模擬工作
            Console.WriteLine($"任務(wù) {id} 結(jié)束。");
        }
        finally
        {
            semaphore.Release(); // 釋放許可
        }
    }
}

輸出示例:

任務(wù) 0 開(kāi)始...
任務(wù) 1 開(kāi)始...
任務(wù) 2 開(kāi)始...
任務(wù) 3 等待中...
任務(wù) 0 結(jié)束。
任務(wù) 3 開(kāi)始...
...

說(shuō)明:同時(shí)最多 3 個(gè)任務(wù)在運(yùn)行。

3.2 限制并發(fā)的 HTTP 請(qǐng)求(爬蟲場(chǎng)景)

using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

class WebCrawler
{
    static readonly HttpClient httpClient = new HttpClient();
    static readonly SemaphoreSlim semaphore = new SemaphoreSlim(5); // 最多5個(gè)并發(fā)

    static async Task Main()
    {
        var urls = new[]
        {
            "https://example.com",
            "https://dotnet.microsoft.com",
            "https://github.com",
            "https://openai.com",
            "https://google.com",
            "https://bing.com"
        };

        var tasks = new Task[urls.Length];
        for (int i = 0; i < urls.Length; i++)
        {
            string url = urls[i];
            tasks[i] = ProcessUrlAsync(url);
        }

        await Task.WhenAll(tasks);
        Console.WriteLine("所有請(qǐng)求完成!");
    }

    static async Task ProcessUrlAsync(string url)
    {
        await semaphore.WaitAsync();
        try
        {
            Console.WriteLine($"開(kāi)始請(qǐng)求:{url}");
            var response = await httpClient.GetAsync(url);
            Console.WriteLine($"{url} 返回狀態(tài)碼:{response.StatusCode}");
        }
        finally
        {
            semaphore.Release();
        }
    }
}

效果:同一時(shí)間最多有 5 個(gè)請(qǐng)求在執(zhí)行,防止網(wǎng)絡(luò)或服務(wù)器過(guò)載。

3.3 控制文件寫入任務(wù)

多個(gè)線程同時(shí)寫同一個(gè)文件時(shí),可以用 SemaphoreSlim 控制訪問(wèn)速率。

using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

class FileWriter
{
    static SemaphoreSlim semaphore = new SemaphoreSlim(1); // 一次僅允許1個(gè)線程寫文件

    static async Task Main()
    {
        var tasks = new Task[5];
        for (int i = 0; i < 5; i++)
        {
            int id = i;
            tasks[i] = Task.Run(() => WriteLogAsync(id));
        }

        await Task.WhenAll(tasks);
        Console.WriteLine("寫入完成。");
    }

    static async Task WriteLogAsync(int id)
    {
        await semaphore.WaitAsync();
        try
        {
            await File.AppendAllTextAsync("output.txt", $"線程 {id} 在 {DateTime.Now}\n");
            Console.WriteLine($"線程 {id} 寫入完成");
        }
        finally
        {
            semaphore.Release();
        }
    }
}

結(jié)果:日志文件不會(huì)被多個(gè)線程同時(shí)寫入而損壞。

3.4 帶超時(shí)機(jī)制的并發(fā)控制

如果等待太久無(wú)法獲取資源,可設(shè)置超時(shí)防止卡死。

if (await semaphore.WaitAsync(TimeSpan.FromSeconds(2)))
{
    try
    {
        Console.WriteLine("成功獲取資源。");
    }
    finally
    {
        semaphore.Release();
    }
}
else
{
    Console.WriteLine("等待超時(shí),放棄操作。");
}

3.5 在異步隊(duì)列中控制消費(fèi)者數(shù)量

適用于后臺(tái)任務(wù)或消息隊(duì)列處理。

using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;

class QueueProcessor
{
    static SemaphoreSlim semaphore = new SemaphoreSlim(3); // 同時(shí)處理3個(gè)任務(wù)
    static BlockingCollection<int> queue = new BlockingCollection<int>();

    static async Task Main()
    {
        // 模擬生產(chǎn)者
        Task.Run(() =>
        {
            for (int i = 0; i < 10; i++)
            {
                queue.Add(i);
                Console.WriteLine($"生產(chǎn)任務(wù) {i}");
                Thread.Sleep(200);
            }
            queue.CompleteAdding();
        });

        // 消費(fèi)者
        var consumers = new Task[3];
        for (int i = 0; i < consumers.Length; i++)
        {
            consumers[i] = Task.Run(() => ConsumeAsync(i));
        }

        await Task.WhenAll(consumers);
        Console.WriteLine("隊(duì)列處理完成。");
    }

    static async Task ConsumeAsync(int workerId)
    {
        foreach (var item in queue.GetConsumingEnumerable())
        {
            await semaphore.WaitAsync();
            try
            {
                Console.WriteLine($"工作線程 {workerId} 處理任務(wù) {item}");
                await Task.Delay(500);
            }
            finally
            {
                semaphore.Release();
            }
        }
    }
}

效果:任務(wù)生產(chǎn)速度可以高于消費(fèi)速度,但消費(fèi)者數(shù)量始終受控,防止系統(tǒng)過(guò)載。

4、總結(jié)

通過(guò)本文,你已經(jīng)掌握了:

  • SemaphoreSlim 的核心原理與區(qū)別;
  • 如何控制并發(fā)訪問(wèn);
  • 在異步任務(wù)、HTTP 請(qǐng)求、文件 I/O 等場(chǎng)景下的實(shí)戰(zhàn)用法;
  • 如何結(jié)合超時(shí)與限流策略提高系統(tǒng)穩(wěn)定性。
場(chǎng)景說(shuō)明
并發(fā) HTTP 請(qǐng)求控制限制同時(shí)發(fā)起的請(qǐng)求數(shù)
數(shù)據(jù)庫(kù)連接池限制連接數(shù)量,防止連接耗盡
圖片處理任務(wù)限制 CPU 密集型任務(wù)數(shù)
異步隊(duì)列消費(fèi)避免后臺(tái)任務(wù)過(guò)載
API 限流防止接口被濫用或打爆

SemaphoreSlim 是現(xiàn)代 .NET 并發(fā)編程中非常實(shí)用的工具, 能讓你輕松實(shí)現(xiàn)資源保護(hù)、限流與異步協(xié)作。

以上就是C#使用SemaphoreSlim實(shí)現(xiàn)并發(fā)控制與限流策略的實(shí)戰(zhàn)指南的詳細(xì)內(nèi)容,更多關(guān)于C# SemaphoreSlim并發(fā)控制與限流策略的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • C#使用selenium實(shí)現(xiàn)操作瀏覽器并且截圖

    C#使用selenium實(shí)現(xiàn)操作瀏覽器并且截圖

    這篇文章主要為大家詳細(xì)介紹了C#如何使用selenium組件實(shí)現(xiàn)操作瀏覽器并且截圖,文中的示例代碼簡(jiǎn)潔易懂,有需要的小伙伴可以參考一下
    2024-01-01
  • 詳解c#與js的rsa加密互通

    詳解c#與js的rsa加密互通

    這篇文章主要介紹了詳解c#與js的rsa加密互通,幫助大家更好的理解和學(xué)習(xí)使用c#,感興趣的朋友可以了解下
    2021-03-03
  • C#設(shè)置開(kāi)機(jī)啟動(dòng)項(xiàng)、取消開(kāi)機(jī)啟動(dòng)項(xiàng)

    C#設(shè)置開(kāi)機(jī)啟動(dòng)項(xiàng)、取消開(kāi)機(jī)啟動(dòng)項(xiàng)

    這篇文章主要介紹了C#設(shè)置開(kāi)機(jī)啟動(dòng)項(xiàng)、取消開(kāi)機(jī)啟動(dòng)項(xiàng),本文通過(guò)修改注冊(cè)實(shí)現(xiàn),并給出操作代碼,需要的朋友可以參考下
    2015-06-06
  • 字符串和十六進(jìn)制之間的轉(zhuǎn)換方法實(shí)例

    字符串和十六進(jìn)制之間的轉(zhuǎn)換方法實(shí)例

    這篇文章介紹了字符串和十六進(jìn)制之間的轉(zhuǎn)換方法實(shí)例,有需要的朋友可以參考一下
    2013-11-11
  • C# 實(shí)例化接口對(duì)象的方法

    C# 實(shí)例化接口對(duì)象的方法

    下面小編就為大家?guī)?lái)一篇C# 實(shí)例化接口對(duì)象的方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-02-02
  • C#創(chuàng)建WCF服務(wù)控制臺(tái)應(yīng)用程序詳解

    C#創(chuàng)建WCF服務(wù)控制臺(tái)應(yīng)用程序詳解

    這篇文章主要為大家詳細(xì)介紹了C#創(chuàng)建WCF服務(wù)控制臺(tái)應(yīng)用程序,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-07-07
  • C#線程同步的幾種方法總結(jié)

    C#線程同步的幾種方法總結(jié)

    在本篇文章里小編給大家整理的是關(guān)于C#線程同步的幾種方法總結(jié),需要的朋友們可以學(xué)習(xí)下。
    2020-02-02
  • c# 實(shí)現(xiàn)RSA非對(duì)稱加密算法

    c# 實(shí)現(xiàn)RSA非對(duì)稱加密算法

    RSA解決了對(duì)稱加密的一個(gè)不足,比如AES算法加密和解密時(shí)使用的是同一個(gè)秘鑰,因此這個(gè)秘鑰不能公開(kāi),因此對(duì)于需要公開(kāi)秘鑰的場(chǎng)合,我們需要在加密和解密過(guò)程中使用不同的秘鑰,加密使用的公鑰可以公開(kāi),解密使用的私鑰要保密,這就是非對(duì)稱加密的好處?!?/div> 2021-06-06
  • C#、vb.net及SQL判斷指定年份是否為閏年的方法

    C#、vb.net及SQL判斷指定年份是否為閏年的方法

    這篇文章主要介紹了C#、vb.net及SQL判斷指定年份是否為閏年的方法,分別以三種方法實(shí)現(xiàn)了判斷閏年的功能,在進(jìn)行項(xiàng)目開(kāi)發(fā)中具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2014-11-11
  • C#中的事務(wù)用法實(shí)例分析

    C#中的事務(wù)用法實(shí)例分析

    這篇文章主要介紹了C#中的事務(wù)用法,以一個(gè)簡(jiǎn)單實(shí)例形式分析了C#創(chuàng)建及使用事物的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-09-09

最新評(píng)論

邵阳县| 突泉县| 永仁县| 洪泽县| 理塘县| 弥勒县| 万荣县| 洮南市| 黎川县| 泰和县| 富阳市| 营口市| 海伦市| 莱西市| 安吉县| 通河县| 宽甸| 方正县| 营口市| 清河县| 阿拉善盟| 常宁市| 嫩江县| 祁连县| 康定县| 桐乡市| 湟中县| 灌阳县| 吉林省| 家居| 台中县| 井研县| 巴林右旗| 宁强县| 醴陵市| 连南| 驻马店市| 土默特右旗| 四川省| 望江县| 汝南县|