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

c#?理解csredis庫(kù)實(shí)現(xiàn)分布式鎖的詳細(xì)流程

 更新時(shí)間:2022年02月07日 09:29:40   作者:SZMD.ls.nct  
這篇文章主要介紹了c#?理解csredis實(shí)現(xiàn)分布式鎖,該庫(kù)本身已經(jīng)足夠完善,這里我畫(huà)蛇添足一下,為了方便自己的使用,本文通過(guò)實(shí)例代碼給大家詳細(xì)介紹,需要的朋友可以參考下

聲明:

這里首先使用的是csredis,地址是https://github.com/2881099/csredis

該庫(kù)本身已經(jīng)足夠完善,這里我畫(huà)蛇添足一下,為了方便自己的使用。

本身csredis庫(kù)已經(jīng)實(shí)現(xiàn)了完整的加鎖和去鎖的邏輯,這里實(shí)現(xiàn)的與庫(kù)本身所實(shí)現(xiàn)的有以下幾點(diǎn)區(qū)別(csredis實(shí)現(xiàn)代碼位置為:https://github.com/2881099/csredis/blob/bb6d947695770333027f3936f80052041db41b64/src/CSRedisCore/CSRedisClient.cs#L4344,有興趣可以去了解看下)

1. 去掉了csredis的鎖續(xù)租部分的功能,盡量簡(jiǎn)化

2. 將鎖的token的設(shè)定交給外部,使用guid也罷,使用id也行。通過(guò)已知的token,保證了你可以在任意地方以觀察者的身份釋放鎖。

3. 盡量不修改其key的原本值,不添加前綴,防止在觀測(cè)時(shí)出現(xiàn)不必要的麻煩。

邏輯:

加鎖就是set 一個(gè) key ,如果key 存在的情況下則返回失敗。那么典型的命令就是setnx.

一個(gè)鎖顯然是需要一個(gè)過(guò)期時(shí)間的,那么我們可能要用到 expire命令。

釋放鎖則是一個(gè)del命令

查看鎖的值是需要get命令

比較常見(jiàn)的加鎖使用的是setnx,不過(guò)由于redis支持了SETkeytokenNXEX/PXmax-lock-time(sec/millsec) (設(shè)置key token 是否不存在才set 秒數(shù)模式/毫秒數(shù)模式 秒數(shù)或毫秒數(shù)) 這種傳參模式,由此,這里更加推薦使用set 命令。

如果在我們的代碼端執(zhí)行del 則小概率發(fā)生以下情況:

  A 申請(qǐng)鎖set x,過(guò)期時(shí)間為t。

  經(jīng)過(guò)時(shí)間t后,A恰好忙完了,A通過(guò)get命令看看token是否一致,得到結(jié)果發(fā)現(xiàn)一致的。

A決定發(fā)送del到redis服務(wù)器,此時(shí)A恰好網(wǎng)絡(luò)擁堵。

redis服務(wù)器由于鎖x超時(shí),進(jìn)而釋放了鎖x。

  此時(shí)B恰好也申請(qǐng)了鎖x,無(wú)過(guò)期時(shí)間。

A網(wǎng)絡(luò)恢復(fù),del命令發(fā)送成功。

結(jié)果 B的鎖被A釋放了。

幸好redis支持了lua腳本。讓我們得以簡(jiǎn)單的實(shí)現(xiàn)過(guò)期,加鎖,去鎖功能,而不需要自己手動(dòng)timer過(guò)期。

這里要使用到eval命令執(zhí)行腳本。

代碼

using CSRedis;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;

namespace CsRedis.Helper
{
    /// <summary>
    ///  基于csredis的簡(jiǎn)單封裝
    /// </summary>
    public class CsRedisManager
    {
       
        private ConcurrentDictionary<string, CSRedisClient> _serviceNameWithClient;
      
        /// <summary>
        ///  初始化
        /// </summary>
        public void Init()
        {
            _serviceNameWithClient = new ConcurrentDictionary<string, CSRedisClient>();
        }
        ///  獲取業(yè)務(wù)redis服務(wù)
        /// <param name="serviceName"></param>
        /// <returns></returns>
        public CSRedisClient GetRedisClient(string serviceName)
            CSRedisClient result = null;
            _serviceNameWithClient.TryGetValue(serviceName,out result);
            return result;
        ///  添加redis服務(wù)
        /// <param name="connectStr"></param>
        public bool AddRedisClient(string serviceName,string connectStr)
            CSRedisClient cSRedisClient = new CSRedisClient(connectStr);
            return _serviceNameWithClient.TryAdd(serviceName, cSRedisClient);
        ///  設(shè)置字符串型kv 
        /// <param name="key">key</param>
        /// <param name="value">value</param>
        /// <param name="expireSecond">過(guò)期時(shí)間(秒)</param>
        /// <returns>是否成功</returns>
        public bool Set(string serviceName,string key,string value,int expireSecond=-1)
            var redisClient = GetRedisClient(serviceName);
            GetExceptionOfClient(redisClient);
            
            return redisClient.Set(key, value, expireSecond);
           
        ///  獲取相應(yīng)key的值
        /// <param name="key"></param>
        public string Get(string serviceName, string key)
            return redisClient.Get(key);
        ///  如果不存在則執(zhí)行,存在則忽略
        /// <param name="value"></param>
        public bool SetNx(string serviceName, string key, string value)
            var res = redisClient.SetNx(key, value);
            return res;
        ///  帶過(guò)期時(shí)間的setNx
        /// <param name="seconds"></param>
        public bool SetNx(string serviceName, string key, string value, int millSeconds = -1)
            var res = Set(serviceName, key, value, RedisExistence.Nx, millSeconds);
        ///  帶過(guò)期時(shí)間的SetXx
        public bool SetXx(string serviceName, string key, string value, int millSeconds = -1)
            var res = Set(serviceName, key, value, RedisExistence.Xx, millSeconds);
        ///  帶參數(shù)set
        /// <param name="existence"></param>
        public bool Set(string serviceName, string key, string value, RedisExistence existence, int millSeconds = -1)
            var res = redisClient.Set(key, value, millSeconds, existence);
        ///  設(shè)置生存時(shí)間
        public bool Expire(string serviceName, string key, int seconds)
            return redisClient.Expire(key, seconds);
        ///  獲取剩余的生存時(shí)間(秒)
        public long Ttl(string serviceName, string key)
            return redisClient.Ttl(key);
        ///  刪除del
        public long Del(string serviceName,params string[] keys)
            return redisClient.Del(keys);
        ///  執(zhí)行腳本
        /// <param name="script"></param>
        /// <param name="args"></param>
        public object Eval(string serviceName, string script,string key,params object[] args)
            var res = redisClient.Eval(script, key,args);
        ///  添加共享鎖
        public bool AddLock(string serviceName, string key,string token, int millSeconds = -1)
            var valRes = SetNx(serviceName, key, token, millSeconds);
            return valRes;
        ///  刪除共享鎖
        public bool ReleaseLock(string serviceName, string key,string token)
            var script = GetReleaseLockScript();
            var res = redisClient.Eval(script, key, token);
            if (0== (long)res)
            {
                return false;
            }
            return true;
        ///  獲取鍵值
        /// <param name="pattern"></param>
        public string[] Keys(string serviceName, string pattern)
            var res = redisClient.Keys(pattern);
        ///  獲取client發(fā)生異常
        /// <param name="client"></param>
        private void GetExceptionOfClient(CSRedisClient client)
            if (client == null)
                throw new Exception("無(wú)有效的redis服務(wù)");
        ///  lua腳本刪除共享鎖
        ///  解決在A申請(qǐng)鎖 xxkey  過(guò)期的瞬間,B 申請(qǐng)鎖xxkey,
        ///  此時(shí)恰好A執(zhí)行到釋放xxkey從而引起的異常釋放
        private static  string GetReleaseLockScript()
            return "if redis.call(\"get\",KEYS[1]) == ARGV[1] \nthen\nreturn redis.call(\"del\", KEYS[1])\nelse\nreturn 0\nend";
        
    }
    
}

這里我把要單獨(dú)執(zhí)行的lua腳本單獨(dú)提出來(lái)

if redis.call("get",KEYS[1]) == ARGV[1]
then
    return redis.call("del",KEYS[1])
else
    return 0
end

這段腳本對(duì)應(yīng)的是c# 中的GetReleaseLockScript()方法中的文字。

這里我個(gè)人偷了個(gè)懶,按照道理,這里應(yīng)該有個(gè)LoadScriptPath,加載腳本所在位置,調(diào)用的時(shí)候先檢查腳本是否在內(nèi)存中,不在則去LoadScriptPath找對(duì)應(yīng)的腳本,方便不同的人協(xié)同合作。不過(guò)那個(gè)就是腳本管理器了,還要設(shè)計(jì)interface,有點(diǎn)偏離主題了。

下面是測(cè)試代碼

using CsRedis.Helper;
using NUnit.Framework;

namespace TestProject
{
    public class Tests
    {
        [SetUp]
        public void Setup()
        {
        }
        [Test]
        public void Test1()
            CsRedisManager csRedisManager = new CsRedisManager();
            csRedisManager.Init();
            csRedisManager.AddRedisClient("TEST", "127.0.0.1:6379,password=123456, connectTimeout =1000,connectRetry=1,syncTimeout=10000,defaultDatabase=0");
            //csRedisManager.AddRedisClient("PRODUCT", "127.0.0.1:6379,password=123456, connectTimeout =1000,connectRetry=1,syncTimeout=10000,defaultDatabase=1");
            
            var token = "123";
            var lockKey = "LOCKKEY1";
            csRedisManager.AddLock("TEST", lockKey,token,20 * 1000);
            csRedisManager.ReleaseLock("TEST", lockKey, token);
    }
}

這里就是對(duì)于共享鎖的一點(diǎn)簡(jiǎn)單實(shí)現(xiàn),多了挺多與本次的命令無(wú)關(guān)的代碼,海涵海涵

到此這篇關(guān)于c# 理解csredis實(shí)現(xiàn)分布式鎖的文章就介紹到這了,更多相關(guān)c# 分布式鎖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 如何在C#中使用 CancellationToken 處理異步任務(wù)

    如何在C#中使用 CancellationToken 處理異步任務(wù)

    這篇文章主要介紹了如何在C#中使用 CancellationToken 處理異步任務(wù),幫助大家更好的理解和學(xué)習(xí)使用c#,感興趣的朋友可以了解下
    2021-03-03
  • C# WinForm實(shí)現(xiàn)鼠標(biāo)穿透功能

    C# WinForm實(shí)現(xiàn)鼠標(biāo)穿透功能

    在WinForm開(kāi)發(fā)時(shí),會(huì)用到這樣一個(gè)場(chǎng)景,給屏幕增加水印Logo,但不影響畫(huà)面的操作,這里就會(huì)用到鼠標(biāo)穿透功能,下面我們就來(lái)學(xué)習(xí)一下鼠標(biāo)穿透功能的具體實(shí)現(xiàn)吧
    2023-11-11
  • 判斷圖片-判斷位圖是否是黑白圖片的方法

    判斷圖片-判斷位圖是否是黑白圖片的方法

    近來(lái)工作需要判斷圖片否是是彩色的,由于是十萬(wàn)張以上的大批量理處,所以通過(guò)序程來(lái)動(dòng)自判斷。
    2013-05-05
  • 淺談C#手機(jī)號(hào)換成111XXXX1111 這種顯示的解決思路

    淺談C#手機(jī)號(hào)換成111XXXX1111 這種顯示的解決思路

    下面小編就為大家?guī)?lái)一篇淺談C#手機(jī)號(hào)換成111XXXX1111 這種顯示的解決思路。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-11-11
  • C#實(shí)現(xiàn)DataTable轉(zhuǎn)TXT、CSV文件

    C#實(shí)現(xiàn)DataTable轉(zhuǎn)TXT、CSV文件

    這篇文章介紹了C#實(shí)現(xiàn)DataTable轉(zhuǎn)TXT、CSV文件的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-04-04
  • 在Parallel中使用DbSet.Add()發(fā)現(xiàn)的一系列多線程問(wèn)題和解決思路詳解

    在Parallel中使用DbSet.Add()發(fā)現(xiàn)的一系列多線程問(wèn)題和解決思路詳解

    這篇文章主要介紹了在Parallel中使用DbSet.Add()發(fā)現(xiàn)的一系列多線程問(wèn)題和解決過(guò)程的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2016-11-11
  • 淺談C#數(shù)組(一)

    淺談C#數(shù)組(一)

    本篇文章小編要得大家介紹的是C#數(shù)組,數(shù)組是一種數(shù)據(jù)結(jié)構(gòu),它可以包含同一個(gè)類型的多個(gè)元素,如果需要使用同一類型的多個(gè)對(duì)象,可以使用數(shù)組和集合,需要的朋友可以參考下面文章的具體內(nèi)容
    2021-09-09
  • C# 遍歷文件夾子目錄下所有圖片及遍歷文件夾下的文件

    C# 遍歷文件夾子目錄下所有圖片及遍歷文件夾下的文件

    在上個(gè)項(xiàng)目開(kāi)發(fā)中遇到這樣的需求,取指定目錄下面的所有圖片,以表格的型式展示并顯示該圖片的相對(duì)路徑。下面小編給大家分享C# 遍歷文件夾子目錄下所有圖片及遍歷文件夾下的文件,一起看看吧
    2017-01-01
  • C#實(shí)現(xiàn)WinForm控件焦點(diǎn)的獲取與失去

    C#實(shí)現(xiàn)WinForm控件焦點(diǎn)的獲取與失去

    在一個(gè)數(shù)據(jù)輸入表單中,當(dāng)用戶從一個(gè)文本框切換到另一個(gè)文本框時(shí),需要準(zhǔn)確地判斷焦點(diǎn)的轉(zhuǎn)移,以便進(jìn)行數(shù)據(jù)驗(yàn)證、提示信息顯示等操作,本文將探討 Winform 控件獲取與失去焦點(diǎn)的相關(guān)知識(shí),需要的朋友可以參考下
    2025-01-01
  • C#驗(yàn)證身份證的函數(shù)

    C#驗(yàn)證身份證的函數(shù)

    因做項(xiàng)目需要,參考網(wǎng)上資料寫(xiě)了一個(gè)身份證驗(yàn)證的C#方法,本方法是在VS2005[C/S] 下寫(xiě)的。前面2個(gè)是網(wǎng)友們的實(shí)現(xiàn)方法,第三個(gè)才是項(xiàng)目中使用的哦,小伙伴們參考下吧。
    2015-05-05

最新評(píng)論

册亨县| 喜德县| 武穴市| 嘉鱼县| 甘泉县| 密云县| 秦皇岛市| 平原县| 沂水县| 玉林市| 永清县| 嘉荫县| 江西省| 兴文县| 汕头市| 闽清县| 涞水县| 康定县| 瑞昌市| 时尚| 江川县| 个旧市| 喜德县| 成都市| 长岭县| 改则县| 炎陵县| 玛纳斯县| 扶风县| 孙吴县| 岑巩县| 枝江市| 广平县| 凤冈县| 衢州市| 南和县| 湖北省| 辉南县| 龙州县| 海淀区| 涟水县|