概述

在传统单体应用单机部署的情况下,可以使用Java并发处理相关的API(如ReentrantLock或Synchronized)进行互斥控制。在单机环境中,Java中提供了很多并发处理相关的API。但是,随着业务发展的需要,原单体单机部署的系统被演化成分布式集群系统后,由于分布式系统多线程、多进程并且分布在不同机器上,这将使原单机部署情况下的并发控制锁策略失效,单纯的Java API并不能提供分布式锁的能力。为了解决这个问题就需要一种跨JVM的互斥机制来控制共享资源的访问,这就是分布式锁要解决的问题!

锁是在执行多线程时用于强行限制资源访问的同步机制,在单机系统上,可以使用Java并发处理相关的API(如ReentrantLock或Synchronized)进行互斥控制。而在分布式系统场景下,实例会运行在多台机器上,为了使多进程(多实例上)对共享资源的读写同步,保证数据的最终一致性,引入了分布式锁。

分布式锁应具备以下特点:

  • 互斥性:在任意时刻,只有一个客户端(进程)能持有锁
  • 安全性:避免死锁情况,当一个客户端在持有锁期间内,由于意外崩溃而导致锁未能主动解锁,其持有的锁也能够被正确释放,并保证后续其它客户端也能加锁
  • 可用性:分布式锁需要有一定的高可用能力,当提供锁的服务节点故障(宕机)时不影响服务运行,避免单点风险,如Redis的集群模式、哨兵模式,ETCD/zookeeper的集群选主能力等保证HA,保证自身持有的数据与故障节点一致。
  • 对称性:对同一个锁,加锁和解锁必须是同一个进程,即不能把其他进程持有的锁给释放了,这又称为锁的可重入性。

分布式锁常见实现方式:

  1. 通过数据库方式实现:采用乐观锁、悲观锁或者基于主键唯一约束实现
  2. 基于分布式缓存实现的锁服务: Redis 和基于 Redis 的 RedLock(Redisson提供了参考实现)
  3. 基于分布式一致性算法实现的锁服务:ZooKeeper、Chubby(google闭源实现)和 Etcd

网上常见的是基于Redis和ZooKeeper的实现,基于数据库的因为实现繁琐且性能较差,不想维护第三方中间件的可以考虑。本文主要描述基于 ETCD 的实现,etcd3 的client也给出了新的 api,使用上更为简单

基于 Redis 的实现

既然是锁,核心操作无外乎加锁、解锁。

Redis的加锁操作:

SET lock_name my_random_value NX PX 30000
  • lock_name,锁的名称,对于 Redis 而言,lock_name 就是 Key-Value 中的 Key,具有唯一性。
  • random_value,由客户端生成的一个随机字符串,它要保证在足够长的一段时间内,且在所有客户端的所有获取锁的请求中都是唯一的,用于唯一标识锁的持有者。
  • NX 只有当 lock_name(key) 不存在的时候才能 SET 成功,从而保证只有一个客户端能获得锁,而其它客户端在锁被释放之前都无法获得锁。
  • PX 30000 表示这个锁节点有一个 30 秒的自动过期时间(目的是为了防止持有锁的客户端故障后,无法主动释放锁而导致死锁,因此要求锁的持有者必须在过期时间之内执行完相关操作并释放锁)。

Redis的解锁操作:

del lock_name
  • 在加锁时为锁设置过期时间,当过期时间到达,Redis 会自动删除对应的 Key-Value,从而避免死锁。注意,这个过期时间需要结合具体业务综合评估设置,以保证锁的持有者能够在过期时间之内执行完相关操作并释放锁。
  • 正常执行完毕,未到达锁过期时间,通过del lock_name主动释放锁。

基于 ETCD的分布式锁

机制

etcd 支持以下功能,正是依赖这些功能来实现分布式锁的:

  • Lease 机制:即租约机制(TTL,Time To Live),Etcd 可以为存储的 KV 对设置租约,当租约到期,KV 将失效删除;同时也支持续约,即 KeepAlive。
  • Revision 机制:每个 key 带有一个 Revision 属性值,etcd 每进行一次事务对应的全局 Revision 值都会加一,因此每个 key 对应的 Revision 属性值都是全局唯一的。通过比较 Revision 的大小就可以知道进行写操作的顺序。
  • 在实现分布式锁时,多个程序同时抢锁,根据 Revision 值大小依次获得锁,可以避免 “羊群效应” (也称 “惊群效应”),实现公平锁。
  • Prefix 机制:即前缀机制,也称目录机制。可以根据前缀(目录)获取该目录下所有的 key 及对应的属性(包括 key, value 以及 revision 等)。
  • Watch 机制:即监听机制,Watch 机制支持 Watch 某个固定的 key,也支持 Watch 一个目录(前缀机制),当被 Watch 的 key 或目录发生变化,客户端将收到通知。

过程

实现过程:

  • 步骤 1: 准备

客户端连接 Etcd,以 /lock/mylock 为前缀创建全局唯一的 key,假设第一个客户端对应的 key="/lock/mylock/UUID1",第二个为 key="/lock/mylock/UUID2";客户端分别为自己的 key 创建租约 - Lease,租约的长度根据业务耗时确定,假设为 15s;

  • 步骤 2: 创建定时任务作为租约的“心跳”

当一个客户端持有锁期间,其它客户端只能等待,为了避免等待期间租约失效,客户端需创建一个定时任务作为“心跳”进行续约。此外,如果持有锁期间客户端崩溃,心跳停止,key 将因租约到期而被删除,从而锁释放,避免死锁。

  • 步骤 3: 客户端将自己全局唯一的 key 写入 Etcd

进行 put 操作,将步骤 1 中创建的 key 绑定租约写入 Etcd,根据 Etcd 的 Revision 机制,假设两个客户端 put 操作返回的 Revision 分别为 1、2,客户端需记录 Revision 用以接下来判断自己是否获得锁。

  • 步骤 4: 客户端判断是否获得锁

客户端以前缀 /lock/mylock 读取 keyValue 列表(keyValue 中带有 key 对应的 Revision),判断自己 key 的 Revision 是否为当前列表中最小的,如果是则认为获得锁;否则监听列表中前一个 Revision 比自己小的 key 的删除事件,一旦监听到删除事件或者因租约失效而删除的事件,则自己获得锁。

  • 步骤 5: 执行业务

获得锁后,操作共享资源,执行业务代码。

  • 步骤 6: 释放锁

完成业务流程后,删除对应的key释放锁。

实现

自带的 etcdctl 可以模拟锁的使用:


// 第一个终端
$ ./etcdctl lock mutex1
mutex1/326963a02758b52d
​
// 第二终端
$ ./etcdctl lock mutex1
​
// 当第一个终端结束了,第二个终端会显示
mutex1/326963a02758b531

在etcd的clientv3包中,实现了分布式锁。使用起来和mutex是类似的,为了了解其中的工作机制,这里简要的做一下总结。

etcd分布式锁的实现在go.etcd.io/etcd/clientv3/concurrency包中,主要提供了以下几个方法:

* func NewMutex(s *Session, pfx string) *Mutex, 用来新建一个mutex
* func (m *Mutex) Lock(ctx context.Context) error,它会阻塞直到拿到了锁,并且支持通过context来取消获取锁。
* func (m *Mutex) Unlock(ctx context.Context) error,解锁

因此在使用etcd提供的分布式锁式非常简单,通常就是实例化一个mutex,然后尝试抢占锁,之后进行业务处理,最后解锁即可。

demo:

package mainimport (  "context""fmt""github.com/coreos/etcd/clientv3""github.com/coreos/etcd/clientv3/concurrency""log""os""os/signal""time"
)func main() {  c := make(chan os.Signal)signal.Notify(c)cli, err := clientv3.New(clientv3.Config{Endpoints:   []string{"localhost:2379"},DialTimeout: 5 * time.Second,})if err != nil {log.Fatal(err)}defer cli.Close()lockKey := "/lock"go func () {session, err := concurrency.NewSession(cli)if err != nil {log.Fatal(err)}m := concurrency.NewMutex(session, lockKey)if err := m.Lock(context.TODO()); err != nil {log.Fatal("go1 get mutex failed " + err.Error())}fmt.Printf("go1 get mutex sucess\n")fmt.Println(m)time.Sleep(time.Duration(10) * time.Second)m.Unlock(context.TODO())fmt.Printf("go1 release lock\n")}()go func() {time.Sleep(time.Duration(2) * time.Second)session, err := concurrency.NewSession(cli)if err != nil {log.Fatal(err)}m := concurrency.NewMutex(session, lockKey)if err := m.Lock(context.TODO()); err != nil {log.Fatal("go2 get mutex failed " + err.Error())}fmt.Printf("go2 get mutex sucess\n")fmt.Println(m)time.Sleep(time.Duration(2) * time.Second)m.Unlock(context.TODO())fmt.Printf("go2 release lock\n")}()<-c
}

原理

Lock()函数的实现很简单:

// Lock locks the mutex with a cancelable context. If the context is canceled
// while trying to acquire the lock, the mutex tries to clean its stale lock entry.
func (m *Mutex) Lock(ctx context.Context) error {s := m.sclient := m.s.Client()m.myKey = fmt.Sprintf("%s%x", m.pfx, s.Lease())cmp := v3.Compare(v3.CreateRevision(m.myKey), "=", 0)// put self in lock waiters via myKey; oldest waiter holds lockput := v3.OpPut(m.myKey, "", v3.WithLease(s.Lease()))// reuse key in case this session already holds the lockget := v3.OpGet(m.myKey)// fetch current holder to complete uncontended path with only one RPCgetOwner := v3.OpGet(m.pfx, v3.WithFirstCreate()...)resp, err := client.Txn(ctx).If(cmp).Then(put, getOwner).Else(get, getOwner).Commit()if err != nil {return err}m.myRev = resp.Header.Revisionif !resp.Succeeded {m.myRev = resp.Responses[0].GetResponseRange().Kvs[0].CreateRevision}// if no key on prefix / the minimum rev is key, already hold the lockownerKey := resp.Responses[1].GetResponseRange().Kvsif len(ownerKey) == 0 || ownerKey[0].CreateRevision == m.myRev {m.hdr = resp.Headerreturn nil}// wait for deletion revisions prior to myKeyhdr, werr := waitDeletes(ctx, client, m.pfx, m.myRev-1)// release lock key if wait failedif werr != nil {m.Unlock(client.Ctx())} else {m.hdr = hdr}return werr
}

首先通过一个事务来尝试加锁,这个事务主要包含了4个操作: cmp、put、get、getOwner。需要注意的是,key是由pfx和Lease()组成的。

  • cmp: 比较加锁的key的修订版本是否是0。如果是0就代表这个锁不存在。
  • put: 向加锁的key中存储一个空值,这个操作就是一个加锁的操作,但是这把锁是有超时时间的,超时的时间是session的默认时长。超时是为了防止锁没有被正常释放导致死锁。
  • get: get就是通过key来查询
  • getOwner: 注意这里是用m.pfx来查询的,并且带了查询参数WithFirstCreate()。使用pfx来查询是因为其他的session也会用同样的pfx来尝试加锁,并且因为每个LeaseID都不同,所以第一次肯定会put成功。但是只有最早使用这个pfx的session才是持有锁的,所以这个getOwner的含义就是这样的。

接下来才是通过判断来检查是否持有锁

m.myRev = resp.Header.Revision
if !resp.Succeeded {m.myRev = resp.Responses[0].GetResponseRange().Kvs[0].CreateRevision
}
// if no key on prefix / the minimum rev is key, already hold the lock
ownerKey := resp.Responses[1].GetResponseRange().Kvs
if len(ownerKey) == 0 || ownerKey[0].CreateRevision == m.myRev {m.hdr = resp.Headerreturn nil
}

m.myRev是当前的版本号,resp.Succeeded是cmp为true时值为true,否则是false。这里的判断表明当同一个session非第一次尝试加锁,当前的版本号应该取这个key的最新的版本号。

下面是取得锁的持有者的key。如果当前没有人持有这把锁,那么默认当前会话获得了锁。或者锁持有者的版本号和当前的版本号一致, 那么当前的会话就是锁的持有者。

// wait for deletion revisions prior to myKey
hdr, werr := waitDeletes(ctx, client, m.pfx, m.myRev-1)
// release lock key if wait failed
if werr != nil {m.Unlock(client.Ctx())
} else {m.hdr = hdr
}

上面这段代码就很好理解了,因为走到这里说明没有获取到锁,那么这里等待锁的删除。

waitDeletes方法的实现也很简单,但是需要注意的是,这里的getOpts只会获取比当前会话版本号更低的key,然后去监控最新的key的删除。等这个key删除了,自己也就拿到锁了。

这种分布式锁的实现和我一开始的预想是不同的。它不存在锁的竞争,不存在重复的尝试加锁的操作。而是通过使用统一的前缀pfx来put,然后根据各自的版本号来排队获取锁。效率非常的高。避免了惊群效应


如图所示,共有4个session来加锁,那么根据revision来排队,获取锁的顺序为session2 -> session3 -> session1 -> session4。

这里面需要注意一个惊群效应,每一个client在锁住/lock这个path的时候,实际都已经插入了自己的数据,类似/lock/LEASE_ID,并且返回了各自的index(就是raft算法里面的日志索引),而只有最小的才算是拿到了锁,其他的client需要watch等待。例如client1拿到了锁,client2和client3在等待,而client2拿到的index比client3的更小,那么对于client1删除锁之后,client3其实并不关心,并不需要去watch。所以综上,等待的节点只需要watch比自己index小并且差距最小的节点删除事件即可。

基于 ETCD的选主

机制

etcd有多种使用场景,Master选举是其中一种。说起Master选举,过去常常使用zookeeper,通过创建EPHEMERAL_SEQUENTIAL节点(临时有序节点),我们选择序号最小的节点作为Master,逻辑直观,实现简单是其优势,但是要实现一个高健壮性的选举并不简单,同时zookeeper繁杂的扩缩容机制也是沉重的负担。

master 选举根本上也是抢锁,与zookeeper直观选举逻辑相比,etcd的选举则需要在我们熟悉它的一系列基本概念后,调动我们充分的想象力:

  • 1、MVCC,key存在版本属性,没被创建时版本号为0;

  • 2、CAS操作,结合MVCC,可以实现竞选逻辑,if(version == 0) set(key,value),通过原子操作,确保只有一台机器能set成功;

  • 3、Lease租约,可以对key绑定一个租约,租约到期时没预约,这个key就会被回收;

  • 4、Watch监听,监听key的变化事件,如果key被删除,则重新发起竞选。

    至此,etcd选举的逻辑大体清晰了,但这一系列操作与zookeeper相比复杂很多,有没有已经封装好的库可以直接拿来用?etcd clientv3 concurrency中有对选举及分布式锁的封装。后面进一步发现,etcdctl v3里已经有master选举的实现了,下面针对这部分代码进行简单注释,在最后参考这部分代码实现自己的选举逻辑。

实现

官方示例:https://github.com/etcd-io/etcd/blob/master/clientv3/concurrency/example_election_test.go

如crontab 示例:

package mainimport ("context""fmt""go.etcd.io/etcd/clientv3""go.etcd.io/etcd/clientv3/concurrency""log""time"
)const prefix = "/election-demo"
const prop = "local"func main() {endpoints := []string{"szth-cce-devops00.szth.baidu.com:8379"}cli, err := clientv3.New(clientv3.Config{Endpoints: endpoints})if err != nil {log.Fatal(err)}defer cli.Close()campaign(cli, prefix, prop)}func campaign(c *clientv3.Client, election string, prop string) {for {// 租约到期时间:5ss, err := concurrency.NewSession(c, concurrency.WithTTL(5))if err != nil {fmt.Println(err)continue}e := concurrency.NewElection(s, election)ctx := context.TODO()log.Println("开始竞选")err = e.Campaign(ctx, prop)if err != nil {log.Println("竞选 leader失败,继续")switch {case err == context.Canceled:returndefault:continue}}log.Println("获得leader")if err := doCrontab(); err != nil {log.Println("调用主方法失败,辞去leader,重新竞选")_ = e.Resign(ctx)continue}return}
}func doCrontab() error {for {fmt.Println("doCrontab")time.Sleep(time.Second * 4)//return fmt.Errorf("sss")}
}

原理

/** 发起竞选* 未当选leader前,会一直阻塞在Campaign调用* 当选leader后,等待SIGINT、SIGTERM或session过期而退出* https://github.com/etcd-io/etcd/blob/master/etcdctl/ctlv3/command/elect_command.go*/func campaign(c *clientv3.Client, election string, prop string) error {//NewSession函数中创建了一个lease,默认是60s TTL,并会调用KeepAlive,永久为这个lease自动续约(2/3生命周期的时候执行续约操作)s, err := concurrency.NewSession(c)if err != nil {return err}e := concurrency.NewElection(s, election)ctx, cancel := context.WithCancel(context.TODO())donec := make(chan struct{})sigc := make(chan os.Signal, 1)signal.Notify(sigc, syscall.SIGINT, syscall.SIGTERM)go func() {<-sigccancel()close(donec)}()//竞选逻辑,将展开分析if err = e.Campaign(ctx, prop); err != nil {return err}// print key since electedresp, err := c.Get(ctx, e.Key())if err != nil {return err}display.Get(*resp)select {case <-donec:case <-s.Done():return errors.New("elect: session expired")}return e.Resign(context.TODO())
}/** 类似于zookeeper的临时有序节点,etcd的选举也是在相应的prefix path下面创建key,该key绑定了lease并根据lease id进行命名,* key创建后就有revision号,这样使得在prefix path下的key也都是按revision有序* https://github.com/etcd-io/etcd/blob/master/clientv3/concurrency/election.go*/func (e *Election) Campaign(ctx context.Context, val string) error {s := e.sessionclient := e.session.Client()//真正创建的key名为:prefix + lease idk := fmt.Sprintf("%s%x", e.keyPrefix, s.Lease())//Txn:transaction,依靠Txn进行创建key的CAS操作,当key不存在时才会成功创建txn := client.Txn(ctx).If(v3.Compare(v3.CreateRevision(k), "=", 0))txn = txn.Then(v3.OpPut(k, val, v3.WithLease(s.Lease())))txn = txn.Else(v3.OpGet(k))resp, err := txn.Commit()if err != nil {return err}e.leaderKey, e.leaderRev, e.leaderSession = k, resp.Header.Revision, s//如果key已存在,则创建失败;//当key的value与当前value不等时,如果自己为leader,则不用重新执行选举直接设置value;//否则报错。if !resp.Succeeded {kv := resp.Responses[0].GetResponseRange().Kvs[0]e.leaderRev = kv.CreateRevisionif string(kv.Value) != val {if err = e.Proclaim(ctx, val); err != nil {e.Resign(ctx)return err}}}//一直阻塞,直到确认自己的create revision为当前path中最小,从而确认自己当选为leader_, err = waitDeletes(ctx, client, e.keyPrefix, e.leaderRev-1)if err != nil {// clean up in case of context cancelselect {case <-ctx.Done():e.Resign(client.Ctx())default:e.leaderSession = nil}return err}e.hdr = resp.Headerreturn nil
}

锁基础:

https://tech.meituan.com/2018/11/15/java-lock.html

Reference

  • https://godoc.org/go.etcd.io/etcd/clientv3/concurrency#Mutex.Lock
  • 三种分布式锁实现:https://juejin.im/post/5bbb0d8df265da0abd3533a5
  • http://harlon.org/2018/04/14/distributedsystemlock/
  • http://wuwenliang.net/2019/07/23/%E5%86%8D%E8%B0%88%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81%E4%B9%8B%E5%89%96%E6%9E%90Redis%E5%AE%9E%E7%8E%B0/
  • https://www.myway5.com/index.php/2019/10/09/etcd%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81%E7%9A%84%E5%AE%9E%E7%8E%B0%E6%96%B9%E5%BC%8F/
  • https://github.com/jinhailang/blog/issues/47
  • https://cloud.tencent.com/developer/article/1458456
  • https://github.com/etcd-io/etcd/blob/master/clientv3/concurrency/example_election_test.go
  • https://tech.meituan.com/2018/11/15/java-lock.html
查看全文
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

相关文章

  1. pat-B1001-害死人不偿命的(3n+1)猜想

    题目链接->link 思路依题意判断奇偶累计即可。代码 #include <stdio.h> #include <math.h> #include <string.h> #include <iostream>using namespace std;int main(){int n,count=0;scanf("%d",&n);while(n!=1){if(n%2==0){n/=2;cou…...

    2024/5/7 0:42:54
  2. PAT乙级真题1093 || 字符串A+B(详解,C/C++示例,测试点分析)

    【欢迎关注微信公众号:计算机黑科学大全,在对话框回复:PAT乙级真题】获取全部真题详解及代码示例,邀请大家加入PAT算法刷题交流qq群:821388108 个人博客:https://mzwang.top字符串A+B 题目描述: 给定两个字符串 A 和 B,本题要求你输出 A+B,即两个字符串的并集。要求先…...

    2024/5/7 0:42:49
  3. 寒假集训_专题四题解_E - Revenge of GCD

    题目 In mathematics, the greatest common divisor (gcd), also known as the greatest common factor (gcf), highest common factor (hcf), or greatest common measure (gcm), of two or more integers (when at least one of them is not zero), is the largest positive …...

    2024/5/7 0:42:45
  4. spring boot项目解决前后端分离跨域问题

    Spring Boot项目,最开始解决跨域,是在Controller使用注解:@CrossOrigin后来发现,每个Controller都写这个注解很麻烦,于是找了个配置文件,直接解决: /*** AJAX请求跨域*/ @Configuration public class CorsConfig implements WebMvcConfigurer {static final String ORIG…...

    2024/5/6 2:52:45
  5. 解决redis \xe5\xbe\xae\xe4\xbf\xa1\xe6\x94\xaf\xe4\xbb\乱码问题

    redis-cli --rawredis-cli链接的话,在后面加个参数--raw如果是docker如下:docker exec -ti dba64378f084 redis-cli --raw...

    2024/5/7 0:42:37
  6. Hdu1012:计算e(java实现)

    原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=1012题目名称:计算e问题描述: 输入项: 无测试用例: 无public class Hdu1012 {public static void main(String[] args) {for (int i = 0; i <= 9; i++) {System.out.println("i为" + i + "时求…...

    2024/5/7 0:42:33
  7. 容器内外应用与非容器应用之间互访方式

    Docker中常用的三种网络种类bridge,应用都是容器形式,且都在一个宿主机上,各个容器需要互相通信的场景; host,容器和本机应用混杂且需要相互访问的情况;容器会使用宿主机的网络 overlay,在不同宿主机的容器之间需要互相通信的情景。注:docker中的网络常用的分为host(如…...

    2024/5/7 0:42:30
  8. 关于竞争条件的对策

    原子操作TOCTTOU竞争条件是由于检查操作和使用操作之间的间隔(也称窗口期)而导致的,原子操作旨在消除检查和使用操作之间的间隔,将检查和使用操作原子化,该对策需要操作系统级的支持。重复检查和使用 竞争条件漏洞能否成功被利用,取决于攻击者能否赢得检查与使用之间的窗…...

    2024/5/7 0:42:25
  9. 图片消噪与灰度处理

    图片消噪 scipy.fftpack模块用来计算快速傅里叶变换 速度比传统傅里叶变换更快,是对之前算法的改进 图片是二维数据,注意使用fftpack的二维转变方法 moon = plt.imread(moonlanding.png) plt.figure(figsize=(12,8)) plt.imshow(moon, cmap=plt.cm.gray) # gray加载图片# ff…...

    2024/5/7 0:42:21
  10. hadoop配置文件说明

    ...

    2024/5/7 0:42:17
  11. Lilnux-kafka的一些基本命令

    node01改成localhost或者127.0.0.1 查看所有topic列表 bin/kafka-topics.sh --zookeeper node01:2181 --list 查看指定topic信息 bin/kafka-topics.sh --zookeeper node01:2181 --describe --topic t_cdr 控制台向topic生产数据 bin/kafka-console-producer.sh --broker-list n…...

    2024/5/6 8:21:13
  12. ceph简介

    1、ceph作者sage博士2004年发表。2、ceph特点高性能a、采用crush算法,数据分布均衡b、灾域的隔离,实现各类负载的副本放置规则c、支持上千个存储节点的规模高可用性a副本数可以灵活控制b支持故障域隔离,数据强一致性c故障场景自动修复自愈d没有单点故障 自动管理高可扩展去中…...

    2024/5/7 0:42:13
  13. Python算法学习day4:关于一道亚马逊面试题的情景分析

    题目描述 亚马逊是一家纳斯达克上市公司,通过其财报我们可以解读它在给定时期内的股票走势信息。 这些信息包括每天交易的最高价、最低价以及开盘价。假定你作为交易员,必须在股票开盘时做出买入或卖出的决定。 你负责设计一个算法,根据给定的股价走势信息,决定买入和卖出策…...

    2024/5/7 0:42:09
  14. 【架构-读书笔记】 架构即未来-第1章

    第1章 人员和领导力对扩展性的影响斗众如斗寡,形名是也所有扩展性最成功的产品,最核心的部分是有一群人,他们最初了很多正确的决策,当然偶尔也出现昏招。要想成功,必须有合适的人,合适的行为,合适的工作,合适的时间。...

    2024/5/7 0:42:05
  15. a.vue基础入门项目实战——项目初始化&修改根组件01

    1 创建实战项目(注意:千万不要语法检查)vue init webpack my-sz-one2 基本页面搭建如下图所示/src/components/layout.vue<!-- layout.vue --><template><div><div class="app-header">header</div><div class="app-conten…...

    2024/5/7 0:42:01
  16. 1002:输出第二个整数

    1002:输出第二个整数 时间限制: 1000 ms 内存限制: 65536 KB 提交数: 61870 通过数: 46648 【题目描述】 输入三个整数,整数之间由一个空格分隔,整数是32位有符号整数。把第二个输入的整数输出。 【输入】 只有一行,共三个整数,整数之间由一个空格分隔。整数是…...

    2024/5/7 0:41:57
  17. C51之对I2C总线上接挂两个24C02的读写操作

    ...

    2024/5/7 0:41:54
  18. redis集群笔记

    1 什么是集群(理解) 多个服务器集中再一起 ,去处理同一个业务 集群和分布式概念(理解)2 为什么需要集群 ,集群有什么好处?(理解) 解决 高并发 大数据的问题3 集群的特点(理解) (1) 扩展性 --可以动态的去扩展的服务器 (2) 高可用 --> 具备容错的功能 (错误恢复) (3) 负载…...

    2024/5/7 0:41:49
  19. Mybaties批量插入

    Mybaties 批量插入有两种方式 1.用Java代码循环遍历集合,调取数据库 Mapper// 添加温度值public void addTemperature(Temperature temperature );具体写法如下:List<Temperature> list=new ArrayList<Temperature>();Temperature temperature= temperature=new …...

    2024/5/7 0:41:45
  20. 如何学会递归?

    可能很多人在大一的时候,就已经接触了递归了,不过,我敢保证很多人初学者刚开始接触递归的时候,是一脸懵逼的,我当初也是,给我的感觉就是,递归太神奇了。为了兼顾初学者,我会从最简单的题讲起!递归的三大要素 第一要素:明确你这个函数想要干什么而这个,是完全由你自己…...

    2024/5/7 0:41:41

最新文章

  1. JMS详细介绍

    JMS JMS&#xff08;Java Message Service&#xff09;是Java平台中用于在不同应用程序之间进行异步消息传递的API&#xff08;Application Programming Interface&#xff09;。它为开发人员提供了在分布式环境下发送、接收和处理消息的标准方式。JMS提供了可靠性、安全性和可…...

    2024/5/8 8:53:52
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/5/7 10:36:02
  3. 【python】Flask Web框架

    文章目录 WSGI(Web服务器网关接口)示例Web应用程序Web框架Flask框架创建项目安装Flask创建一个基本的 Flask 应用程序调试模式路由添加变量构造URLHTTP方法静态文件模板—— Jinja2模板文件(Template File)<...

    2024/5/8 1:34:38
  4. 逆向案例十二——看准网企业信息json格式的信息

    网址&#xff1a;【全国公司排行|排名榜单|哪家好】-看准网 打开开发者工具——刷新——网络——XHR——下滑页面加载新的页面——找到数据包 发现参数加密&#xff0c;返回的数据也进行了加密 按关键字在下方搜索 kiv进入第一个js文件 ctrlf打开文件里面的搜索框继续搜kiv找到…...

    2024/5/7 18:56:56
  5. 【外汇早评】美通胀数据走低,美元调整

    原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...

    2024/5/8 6:01:22
  6. 【原油贵金属周评】原油多头拥挤,价格调整

    原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...

    2024/5/7 9:45:25
  7. 【外汇周评】靓丽非农不及疲软通胀影响

    原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...

    2024/5/4 23:54:56
  8. 【原油贵金属早评】库存继续增加,油价收跌

    原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...

    2024/5/7 14:25:14
  9. 【外汇早评】日本央行会议纪要不改日元强势

    原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...

    2024/5/4 23:54:56
  10. 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响

    原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...

    2024/5/4 23:55:05
  11. 【外汇早评】美欲与伊朗重谈协议

    原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...

    2024/5/4 23:54:56
  12. 【原油贵金属早评】波动率飙升,市场情绪动荡

    原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...

    2024/5/7 11:36:39
  13. 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试

    原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...

    2024/5/4 23:54:56
  14. 【原油贵金属早评】市场情绪继续恶化,黄金上破

    原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...

    2024/5/6 1:40:42
  15. 【外汇早评】美伊僵持,风险情绪继续升温

    原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...

    2024/5/4 23:54:56
  16. 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势

    原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...

    2024/5/4 23:55:17
  17. 氧生福地 玩美北湖(上)——为时光守候两千年

    原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...

    2024/5/7 9:26:26
  18. 氧生福地 玩美北湖(中)——永春梯田里的美与鲜

    原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...

    2024/5/4 23:54:56
  19. 氧生福地 玩美北湖(下)——奔跑吧骚年!

    原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...

    2024/5/4 23:55:06
  20. 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!

    原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...

    2024/5/5 8:13:33
  21. 「发现」铁皮石斛仙草之神奇功效用于医用面膜

    原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...

    2024/5/4 23:55:16
  22. 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者

    原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...

    2024/5/4 23:54:58
  23. 广州械字号面膜生产厂家OEM/ODM4项须知!

    原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...

    2024/5/6 21:42:42
  24. 械字号医用眼膜缓解用眼过度到底有无作用?

    原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...

    2024/5/4 23:54:56
  25. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

    2022/11/19 21:17:18
  26. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

    2022/11/19 21:17:16
  27. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  28. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  29. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

    2022/11/19 21:17:13
  30. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  31. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

    2022/11/19 21:17:11
  32. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

    2022/11/19 21:17:10
  33. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  34. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

    2022/11/19 21:17:08
  35. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  36. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  37. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  38. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  39. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

    2022/11/19 21:17:02
  40. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  41. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

    2022/11/19 21:17:00
  42. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  43. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  44. 如何在iPhone上关闭“请勿打扰”

    Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

    2022/11/19 21:16:57