日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

基于 Redis 实现 CAS 操作

發(fā)布時間:2023/12/4 数据库 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 基于 Redis 实现 CAS 操作 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

基于 Redis 實現(xiàn) CAS 操作

Intro

在 .NET 里并發(fā)情況下我們可以使用 Interlocked.CompareExchange 來實現(xiàn) CAS (Compare And Swap) 操作,在分布式的情景下很多時候我們都會使用 Redis ,最近在改之前做的一個微信小游戲項目,之前是單機(jī)運行的,有些數(shù)據(jù)存儲是基于內(nèi)存的,直接基于對象操作的,最近要改成支持分布式的,于是引入了 redis,原本基于內(nèi)存的數(shù)據(jù)就要遷移到 redis 中存儲,原來的代碼里有一些地方使用了 Interlocked.CompareExchange 來實現(xiàn) CAS 操作,遷移到 redis 中之后也需要類似的功能,于是就想基于 redis 實現(xiàn) CAS 操作。

CAS

CAS (Compare And Swap) 通常可以使用在并發(fā)操作中更新某一個對象的值,CAS 是無鎖操作,CAS 相當(dāng)于是一種樂觀鎖,而直接加鎖相當(dāng)于是悲觀鎖,所以相對來說 CAS 操作 是會比直接加鎖更加高效的。(——個人理解)

Redis Lua

redis 從 2.6.0 版本開始支持 Lua 腳本,Lua 腳本的執(zhí)行是原子性的,所以我們在實現(xiàn)基于 redis 的分布式鎖釋放鎖的時候或者下面要介紹的實現(xiàn)CAS 操作的,要執(zhí)行多個操作但是希望操作是原子操作的時候就可以借助 Lua 腳本來實現(xiàn)(也可以使用事務(wù)來做)

基于 Redis Lua 實現(xiàn) CAS

String CAS Lua Script:

KEYS[1] 對應(yīng)要操作的String 類型的 redis 緩存的 key,ARGV[1]對應(yīng)要比較的值,值相同則更新成 ARGV[2],并返回 1,否則返回 0

if redis.call(""get"", KEYS[1]) == ARGV[1] thenredis.call(""set"", KEYS[1], ARGV[2])return 1 elsereturn 0 end

Hash CAS Lua Script:

KEYS[1] 對應(yīng)要操作的 Hash 類型的 redis 緩存的 key,ARGV[1] 對應(yīng) Hash 的 field,ARGV[2]對應(yīng)要比較的值,值相同則更新成 ARGV[3],并返回 1,否則返回 0

if redis.call(""hget"", KEYS[1], ARGV[1]) == ARGV[2] thenredis.call(""hset"", KEYS[1], ARGV[1], ARGV[3])return 1 elsereturn 0 end

基于 StackExchange.Redis 的實現(xiàn)

為了方便使用,基于 IDatabase 提供了幾個方便使用的擴(kuò)展方法,實現(xiàn)如下:

public static bool StringCompareAndExchange(this IDatabase db, RedisKey key, RedisValue newValue, RedisValue originValue) {return (int)db.ScriptEvaluate(StringCasLuaScript, new[] { key }, new[] { originValue, newValue }) == 1; } public static async Task<bool> StringCompareAndExchangeAsync(this IDatabase db, RedisKey key, RedisValue newValue, RedisValue originValue) {return await db.ScriptEvaluateAsync(StringCasLuaScript, new[] { key }, new[] { originValue, newValue }).ContinueWith(r => (int)r.Result == 1); } public static bool HashCompareAndExchange(this IDatabase db, RedisKey key, RedisValue field, RedisValue newValue, RedisValue originValue) {return (int)db.ScriptEvaluate(HashCasLuaScript, new[] { key }, new[] { field, originValue, newValue }) == 1; } public static async Task<bool> HashCompareAndExchangeAsync(this IDatabase db, RedisKey key, RedisValue field, RedisValue newValue, RedisValue originValue) {return await db.ScriptEvaluateAsync(HashCasLuaScript, new[] { key }, new[] { field, originValue, newValue }).ContinueWith(r => (int)r.Result == 1); }

實際使用

使用可以參考下面的測試代碼:

[Fact] public void StringCompareAndExchangeTest() {var key = "test:String:cas";var redis = DependencyResolver.Current.GetRequiredService<IConnectionMultiplexer>().GetDatabase();redis.StringSet(key, 1);// set to 3 if now is 2Assert.False(redis.StringCompareAndExchange(key, 3, 2));Assert.Equal(1, redis.StringGet(key));// set to 4 if now is 1Assert.True(redis.StringCompareAndExchange(key, 4, 1));Assert.Equal(4, redis.StringGet(key));redis.KeyDelete(key); } [Fact] public void HashCompareAndExchangeTest() {var key = "test:Hash:cas";var field = "testField";var redis = DependencyResolver.Current.GetRequiredService<IConnectionMultiplexer>().GetDatabase();redis.HashSet(key, field, 1);// set to 3 if now is 2Assert.False(redis.HashCompareAndExchange(key, field, 3, 2));Assert.Equal(1, redis.HashGet(key, field));// set to 4 if now is 1Assert.True(redis.HashCompareAndExchange(key, field, 4, 1));Assert.Equal(4, redis.HashGet(key, field));redis.KeyDelete(key); }

References

  • https://redis.io/commands/eval

  • https://redisbook.readthedocs.io/en/latest/feature/scripting.html

  • https://github.com/WeihanLi/WeihanLi.Redis/blob/dev/src/WeihanLi.Redis/RedisExtensions.cs

  • https://github.com/WeihanLi/WeihanLi.Redis/blob/dev/test/WeihanLi.Redis.UnitTest/RedisExtensionsTest.cs

總結(jié)

以上是生活随笔為你收集整理的基于 Redis 实现 CAS 操作的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。