首页 > 数据库 >【redis】互斥锁

【redis】互斥锁

时间:2024-06-14 18:57:15浏览次数:17  
标签:err ctx fmt redis 互斥 context time

1.创建一个Go程序来实现基于Redis的互斥锁。这个程序将尝试获取一个锁,成功后对文件进行操作,并且在完成操作后释放锁

package main

import (
    "context"
    "fmt"
    "github.com/go-redis/redis/v8"
    "os"
    "time"
)

var ctx = context.Background()

func main() {
    // 创建Redis客户端
    rdb := redis.NewClient(&redis.Options{
        Addr:     "localhost:6379", // Redis服务器地址
        Password: "",               // 密码,没有则留空
        DB:       0,                // 使用默认DB
    })

    lockKey := "file_lock"
    lockValue := "1"
    lockTimeout := 10 * time.Second

    // 尝试获取锁
    success, err := rdb.SetNX(ctx, lockKey, lockValue, lockTimeout).Result()
    if err != nil || !success {
        fmt.Println("Failed to acquire the lock.")
        return
    }

    fmt.Println("Lock acquired, processing the file...")

    // 模拟文件操作
    processFile()

    // 释放锁
    _, err = rdb.Del(ctx, lockKey).Result()
    if err != nil {
        fmt.Println("Failed to release the lock.")
        return
    }

    fmt.Println("Lock released.")
}

func processFile() {
    // 模拟对文件的操作,这里只是简单地等待一段时间
    time.Sleep(5 * time.Second)
    fmt.Println("File processed.")
}

解决的问题:

        1.锁的自动过期:为了防止进程在持有锁的状态下异常终止而导致其他进程永远无法获取锁,避免死锁的产生

        2.锁的释放:确保在文件操作完成后正确释放锁是非常重要的,即使在操作过程中遇到错误也应该释放锁,以避免死锁。

引出的问题:

        1.假如文件处理的时间不是固定的,超了10s的过期时间,就会被其他的进程把锁给抢了

2.针对上面的问题,改进的代码:

package main

import (
	"context"
	"fmt"
	"github.com/go-redis/redis/v8"
	"os"
	"sync"
	"time"
)

var ctx = context.Background()

func main() {
	// 创建Redis客户端
	rdb := redis.NewClient(&redis.Options{
		Addr:     "localhost:6379", // Redis服务器地址
		Password: "",               // 密码,没有则留空
		DB:       0,                // 使用默认DB
	})

	lockKey := "file_lock"
	lockValue := "unique_lock_id_" + time.Now().String() // 使用时间戳作为锁的唯一标识
	lockTimeout := 10 * time.Second

	// 尝试获取锁
	success, err := rdb.SetNX(ctx, lockKey, lockValue, lockTimeout).Result()
	if err != nil {
		fmt.Printf("Error trying to acquire the lock: %v\n", err)
		return
	}
	if !success {
		fmt.Println("Lock is already held by another instance.")
		return
	}

	// 使用WaitGroup和context来控制锁续期goroutine的终止
	var wg sync.WaitGroup
	ctx, cancel := context.WithCancel(ctx)
	defer cancel() // 确保在函数退出时取消context

	wg.Add(1)
	go func() {
		defer wg.Done()
		for {
			select {
			case <-ctx.Done():
				return
			case <-time.After(lockTimeout / 2):
				_, err := rdb.Expire(ctx, lockKey, lockTimeout).Result()
				if err != nil {
					fmt.Printf("Error renewing the lock: %v\n", err)
					return
				}
			}
		}
	}()

	fmt.Println("Lock acquired, processing the file...")

	// 模拟文件操作
	processFile()

	// 检查锁的值,确保只有锁的持有者才能释放锁
	val, err := rdb.Get(ctx, lockKey).Result()
	if err != nil {
		// 锁可能已经过期并被其他实例获取
		fmt.Printf("Error getting lock value: %v\n", err)
	} else if val == lockValue {
		_, err = rdb.Del(ctx, lockKey).Result()
		if err != nil {
			fmt.Printf("Error releasing the lock: %v\n", err)
		}
	}

	cancel() // 告诉续期goroutine停止
	wg.Wait() // 等待续期goroutine完成

	fmt.Println("File processed and lock released.")
}

func processFile() {
	// 模拟对文件的操作,这里只是简单地等待一段时间
	time.Sleep(5 * time.Second)
	fmt.Println("File processed.")
}

标签:err,ctx,fmt,redis,互斥,context,time
From: https://blog.csdn.net/m0_64558520/article/details/139687586

相关文章

  • Docker的通俗理解和通过宿主机端口访问Redis容器的实例
    前言本文解决的问题:入门docker理解镜像与容器、宿主机的概念理解Docker的常用指令创建redis容器,并通过宿主机端口访问默认读者的知识背景:使用过git初次使用Docker本文不会对Docker的定义作出解释,不会涉及Docker的实现原理,旨在帮助读者快速入门docker,理解......
  • 一篇文章看懂Redission原理
    文章目录☃️可重入锁原理☃️锁重试和WatchDog机制☃️MutiLock原理上一篇文章讲解了Rediision的使用,这篇文章讲解其原理☃️可重入锁原理在Lock锁中,他是借助于底层的一个voaltile的一个state变量来记录重入的状态的,比如当前没有人持有这把锁,那么state=0,假如有人......
  • Redis之线程IO模型
    引言Redis是个单线程程序!这点必须铭记。除了Redis之外,Node.js也是单线程,Nginx也是单线程,但是他们都是服务器高性能的典范。Redis单线程为什么能够这么快!因为他所有的数据都在内存中,所有的运算都是内存级别的运算。正因为Redis是单线程,所以要小心使用Redis指令,对于那些时......
  • Java面试:Redis如何保证数据一致性?
    Redis是一个内存数据结构存储系统,广泛用于缓存、会话管理等场景。尽管Redis本身不是传统的关系型数据库,它仍然提供了一些机制来保证数据一致性。以下是Redis保证数据一致性的一些方法和机制:1.事务机制(Transactions)Redis支持事务,通过MULTI、EXEC、DISCARD、WATCH等命令实......
  • 【2024最新精简版】Redis面试篇
    文章目录什么是红锁Redis有哪些框架?你们项目中哪里用到了Redis?Redis的常用数据类型有哪些?Redis的数据持久化策略有哪些?Redis的数据过期策略有哪些?Redis的数据淘汰策略有哪些?你们使用Redis是单点还是集群?哪种集群?Redis集群有哪些方案,知道嘛?什么是Red......
  • redis自学(47)批处理优化
    大量数据的导入的方式    Redis提供的批处理方案   M操作比Pipeline快,因为M操作是内部操作,原子操作,而Pipeline不是。  集群下的批处理如MSET或Pipeline这样的批处理需要在一次请求中携带多条命令,而此时如果redis是一个集群,那批处理命令的多个key必须......
  • Redis的两种持久化RDB和AOF
    目录一、简介二、RDB详解三、AOF详解​四、RDB与AOF对比一、简介什么是持久化?利用永久性存储介质将数据进行保存,在特定的时间将保存的数据进行恢复的工作机制称为持久化。说白了Redis是基于内存的,快是快,但一关机数据就没了,这样肯定不行啊,所以就要把数据都存在磁盘上,这......
  • Redis快速入门
    Redis的常见命令和客户端使用1.安装Redis大多数企业都是基于Linux服务器来部署项目,而且Redis官方也没有提供Windows版本的安装包。因此课程中我们会基于Linux系统来安装Redis.此处选择的Linux版本为CentOS7.1.1.依赖库Redis是基于C语言编写的,因此首先需要安装Redis所需要的g......
  • 【redis】使用redis benchmark评估哨兵模式主节点性能
    一、场景   验证redis哨兵模式主节点性能 二、工具Redis benchmark官网Redisbenchmark|Docs 三、命令介绍 四、使用redis-benchmark-h192.168.3.190-p26380-a123456-n100000-c20======PING_INLINE======100000requestscompletedin1.4......
  • 【jmeter】使用beanshell simpler测试redis性能
    一、场景   由于redisdataset支持的类型有限,所以采取使用beanshellsampler 二、安装jedis包https://mvnrepository.com/artifact/redis.clients/jedis 三、添加BeanShellSampler添加脚本importjava.util.Map;importredis.clients.jedis.Jedis;importorg.a......