精华内容
下载资源
问答
  • 声明:版权所有,转载请联系作者并注明出处 ... 用随机梯度下降处理回归 本主题将介绍随机梯度下降法(Stochastic Gradient Descent,SGD),我们将用它解决回归问题,后面我们还用它处理分类问题。

    声明:版权所有,转载请联系作者并注明出处  http://blog.csdn.net/u013719780?viewmode=contents


    博主简介:风雪夜归子(英文名: Allen),机器学习算法攻城狮,喜爱钻研Machine Learning的黑科技,对Deep Learning和Artificial Intelligence充满兴趣,经常关注kaggle数据挖掘竞赛平台,对数据、Machine Learning和Artificial Intelligence有兴趣的各位童鞋可以一起探讨哦,个人CSDN博客: http://blog.csdn.net/u013719780?viewmode=contents


    用随机梯度下降处理回归

    本主题将介绍随机梯度下降法(Stochastic Gradient Descent,SGD),我们将用它解决回归问题,后面我们还用它处理分类问题。

    Getting ready

    SGD是机器学习中的无名英雄(unsung hero),许多算法的底层都有SGD的身影。之所以受欢迎是因为其简便与快速——处理大量数据时这些都是好事儿。

    SGD成为许多机器学习算法的核心的另一个原因是它很容易描述过程。在本章的最后,我们对数据作一些变换,然后用模型的损失函数(loss function)拟合数据。

    How to do it...

    如果SGD适合处理大数据集,我们就用大点儿的数据集来演示:

    In [5]:
    from sklearn import datasets
    X, y = datasets.make_regression(int(1e6))
    print("{:,}".format(int(1e6)))
    
    1,000,000
    

    值得进一步了解数据对象的构成和规模信息。还在我们用的是NumPy数组,所以我们可以获得nbytes。Python本身没有获取NumPy数组大小的方法。输出结果与系统有关,你的结果和下面的数据可能不同:

    In [9]:
    print("{:,}".format(X.nbytes))
    
    800,000,000
    

    我们把字节码nbytes转换成MB(megabytes),看着更直观:

    In [10]:
    X.nbytes / 1e6
    
    Out[10]:
    800.0

    因此,每个数据点的字节数就是:

    In [11]:
    X.nbytes / (X.shape[0] * X.shape[1])
    
    Out[11]:
    8.0

    这些信息和我们的目标没多大关系,不过了解数据对象的构成和规模信息还是值得的。

    现在,我们有了数据,就用SGDRegressor来拟合:

    In [13]:
    import numpy as np
    from sklearn import linear_model
    sgd = linear_model.SGDRegressor()
    train = np.random.choice([True, False], size=len(y), p=[.75, .25])
    sgd.fit(X[train], y[train])
    
    Out[13]:
    SGDRegressor(alpha=0.0001, average=False, epsilon=0.1, eta0=0.01,
           fit_intercept=True, l1_ratio=0.15, learning_rate='invscaling',
           loss='squared_loss', n_iter=5, penalty='l2', power_t=0.25,
           random_state=None, shuffle=True, verbose=0, warm_start=False)

    这里又出现一个“充实的(beefy)”对象。重点需要了解我们的损失函数是squared_loss,与线性回归里的残差平方和是一样的。还需要注意shuffle会对数据产生随机搅动(shuffle),这在解决伪相关问题时很有用。scikit-learn用fit_intercept方法可以自动加一列1。如果想从拟合结果中看到很多输出,就把verbose设为1。用scikit-learn的API预测,我们可以统计残差的分布情况:

    In [16]:
    linear_preds = sgd.predict(X[~train])
    
    In [17]:
    %matplotlib inline
    from matplotlib import pyplot as plt
    f, ax = plt.subplots(figsize=(7, 5))
    f.tight_layout()
    ax.hist(linear_preds - y[~train],label='Residuals Linear', color='b', alpha=.5);
    ax.set_title("Residuals")
    ax.legend(loc='best');
    

    拟合的效果非常好。异常值很少,直方图也呈现出完美的正态分布钟形图。

    How it works...

    当然这里我们用的是虚拟数据集,但是你也可以用更大的数据集合。例如,如果你在华尔街工作,有可能每天一个市场都有20亿条交易数据。现在如果有一周或一年的数据,用SGD算法就可能无法运行了。很难处理这么大的数据量,因为标准的梯度下降法每一步都要计算梯度,计算量非常庞大。

    标准的梯度下降法的思想是在每次迭代计算一个新的相关系数矩阵,然后用学习速率(learning rate)和目标函数(objective function)的梯度调整它,直到相关系数矩阵收敛为止。如果用伪代码写就是这样:

    while not_converged:
        w = w – learning_rate * gradient(cost(w))

    这里涉及的变量包括:

    • w:相关系数矩阵
    • learning_rate:每次迭代时前进的长度。如果收敛效果不好,调整这个参数很重要
    • gradient:导数矩阵
    • cost:回归的残差平方和。后面我们会介绍,不同的分类方法中损失函数定义不同,具有可变性也是SGD应用广泛的理由之一。

    除了梯度函数有点复杂之外,这个方法还是可以的。随着相关系数向量的增加,梯度的计算也会变得越来越慢。每次更新之前,我们都需要对每个数据点计算新权重。

    SGD的工作方式稍有不同;每次迭代不是批量更新梯度,而是只更新新数据点的参数。这些数据点是随机选择的,因此称为随机梯度下降法。


    展开全文
  • 接口幂等问题处理

    千次阅读 2019-09-10 13:41:28
    接口幂等问题处理理论幂等概念幂等场景实践利用redis加锁代码实现利用Redisson高性能分布式锁代码实现(AOP实现)添加maven依赖RedissionConfig配置类:定义注解类注解业务实现类:controller层使用注解测试...


    在这里插入图片描述

    理论

    幂等性概念

    一个幂等操作的特点是任意执行多少次与执行一次产生的影响都是一样的。
    幂等函数
    或幂等方法是指可以使用相同参数重复执行,并能获得相同结果的函数。这些函数不会影响系统状态,也不用担心重复执行会对系统造成改变。例如,“getUsername()和setTrue()”函数就是一个幂等函数. 更复杂的操作幂等保证是利用唯一交易号(流水号)实现。

    幂等性场景

    • 1、查询操作:查询一次和查询多次,在数据不变的情况下,查询结果是一样的。select是天然的幂等操作;

    • 2、删除操作:删除操作也是幂等的,删除一次和多次删除都是把数据删除。(注意可能返回结果不一样,删除的数据不存在,返回0,删除的数据多条,返回结果多个) ;

    • 3、唯一索引:防止新增脏数据。比如:支付宝的资金账户,支付宝也有用户账户,每个用户只能有一个资金账户,怎么防止给用户创建资金账户多个,那么给资金账户表中的用户ID加唯一索引,所以一个用户新增成功一个资金账户记录。要点:唯一索引或唯一组合索引来防止新增数据存在脏数据(当表存在唯一索引,并发时新增报错时,再查询一次就可以了,数据应该已经存在了,返回结果即可);

    • 4、token机制:防止页面重复提交。
      原理上通过session token来实现的(也可以通过redis来实现)。当客户端请求页面时,服务器会生成一个随机数Token,并且将Token放置到session当中,然后将Token发给客户端(一般通过构造hidden表单)。 下次客户端提交请求时,Token会随着表单一起提交到服务器端。
      服务器端第一次验证相同过后,会将session中的Token值更新下,若用户重复提交,第二次的验证判断将失败,因为用户提交的表单中的Token没变,但服务器端session中Token已经改变了。

    • 5、悲观锁 获取数据的时候加锁获取。select * from table_xxx where id=‘xxx’ for update; 注意:id字段一定是主键或者唯一索引,不然是锁表,会死人的;悲观锁使用时一般伴随事务一起使用,数据锁定时间可能会很长,根据实际情况选用;

    • 6、乐观锁——乐观锁只是在更新数据那一刻锁表,其他时间不锁表,所以相对于悲观锁,效率更高。乐观锁的实现方式多种多样可以通过version或者其他状态条件:
      a、通过版本号实现update tablexxx set name=#name#,version=version+1 where version=#version#如下图(来自网上);
      b、通过条件限制 update tablexxx set avaiamount=avaiamount-#subAmount# where avai_amount-#subAmount# >= 0要求:quality-#subQuality# >= ,这个情景适合不用版本号,只更新是做数据安全校验,适合库存模型,扣份额和回滚份额,性能更高;

    • 7、分布式锁
      如果是分布是系统,构建全局唯一索引比较困难,例如唯一性的字段没法确定,这时候可以引入分布式锁,通过第三方的系统(redis或zookeeper),在业务系统插入数据或者更新数据,获取分布式锁,然后做操作,之后释放锁,这样其实是把多线程并发的锁的思路,引入多多个系统,也就是分布式系统中得解决思路。要点:某个长流程处理过程要求不能并发执行,可以在流程执行之前根据某个标志(用户ID+后缀等)获取分布式锁,其他流程执行时获取锁就会失败,也就是同一时间该流程只能有一个能执行成功,执行完成后,释放分布式锁(分布式锁要第三方系统提供);

    • 8、select + insert 并发不高的后台系统,或者一些任务JOB,为了支持幂等,支持重复执行,简单的处理方法是,先查询下一些关键数据,判断是否已经执行过,在进行业务处理,就可以了。注意:核心高并发流程不要用这种方法;

    • 9、状态机幂等 在设计单据相关的业务,或者是任务相关的业务,肯定会涉及到状态机(状态变更图),就是业务单据上面有个状态,状态在不同的情况下会发生变更,一般情况下存在有限状态机,这时候,如果状态机已经处于下一个状态,这时候来了一个上一个状态的变更,理论上是不能够变更的,这样的话,保证了有限状态机的幂等。注意:订单等单据类业务,存在很长的状态流转,一定要深刻理解状态机,对业务系统设计能力提高有很大帮助

    • 10、对外提供接口的api如何保证幂等
      如银联提供的付款接口:需要接入商户提交付款请求时附带:source来源,seq序列号;source+seq在数据库里面做唯一索引,防止多次付款(并发时,只能处理一个请求) 。 重点:对外提供接口为了支持幂等调用,接口有两个字段必须传,一个是来源source,一个是来源方序列号seq,这个两个字段在提供方系统里面做联合唯一索引,这样当第三方调用时,先在本方系统里面查询一下,是否已经处理过,返回相应处理结果;没有处理过,进行相应处理,返回结果。注意,为了幂等友好,一定要先查询一下,是否处理过该笔业务,不查询直接插入业务系统,会报错,但实际已经处理了

    实践

    talk is cheap, show you the code

    1、redis加锁代码实现

    // Copyright 2016-2101 Pica.
    package com.pica.cloud.commercialization.crrs.util;
    
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.stereotype.Component;
    
    import java.util.UUID;
    import java.util.concurrent.TimeUnit;
    
    /**
     * @ClassName RedisLock
     * @Description
     * @Author Chongwen.jiang
     * @Date 2019/9/10 9:44
     * @ModifyDate 2019/9/10 9:44
     * @Version 1.0
     */
    @Slf4j
    @Component
    public class RedisLock {
    
        @Autowired
        private RedisTemplate redisTemplate;
    
        /**
         * @Description 添加元素
         * @Author Chongwen.jiang
         * @Date 2019/9/10 9:47
         * @ModifyDate 2019/9/10 9:47
         * @Params [key, value]
         * @Return void
         */
        public void set(Object key, Object value) {
            if (key == null || value == null) {
                return;
            }
            redisTemplate.opsForValue().set(key, value.toString());
        }
    
        /**
         * @Description 获取数据
         * @Author Chongwen.jiang
         * @Date 2019/9/10 9:49
         * @ModifyDate 2019/9/10 9:49
         * @Params [key]
         * @Return java.lang.Object
         */
        public Object get(Object key) {
            if (key == null) {
                return null;
            }
            return redisTemplate.opsForValue().get(key);
        }
    
        /**
         * @Description 删除
         * @Author Chongwen.jiang
         * @Date 2019/9/10 9:49
         * @ModifyDate 2019/9/10 9:49
         * @Params [key]
         * @Return java.lang.Boolean
         */
        private Boolean remove(Object key) {
            if (key == null) {
                return false;
            }
            return redisTemplate.delete(key);
        }
    
        /**
         * @Description 如果已经存在返回false,否则返回true
         * @Author Chongwen.jiang
         * @Date 2019/9/10 9:48
         * @ModifyDate 2019/9/10 9:48
         * @Params [key, value, expireTime, mimeUnit]
         * @Return java.lang.Boolean
         */
        private Boolean setNx(Object key, Object value, Long expireTime, TimeUnit mimeUnit) {
            if (key == null || value == null) {
                return false;
            }
            return redisTemplate.opsForValue().setIfAbsent(key, value, expireTime, mimeUnit);
        }
    
        /**
         * @Description 加锁
         * @Author Chongwen.jiang
         * @Date 2019/9/10 9:50
         * @ModifyDate 2019/9/10 9:50
         * @Params [key(缓存key), waitTime(等待时间,毫秒), expireTime(key过期时间,毫秒)]
         * @Return java.lang.Boolean
         */
        public Boolean lock(String key, Long waitTime, Long expireTime) {
            String value = UUID.randomUUID().toString().replaceAll("-", "").toLowerCase();
    
            Boolean flag = setNx(key, value, expireTime, TimeUnit.MILLISECONDS);
            // 尝试获取锁 成功返回
            if (flag) {
                return flag;
            } else {
                // 获取失败
    
                // 现在时间
                long newTime = System.currentTimeMillis();
    
                // 等待过期时间
                long loseTime = newTime + waitTime;
    
                // 不断尝试获取锁成功返回
                while (System.currentTimeMillis() < loseTime) {
                    Boolean testFlag = setNx(key, value, expireTime, TimeUnit.MILLISECONDS);
                    if (testFlag) {
                        return testFlag;
                    }
    
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
            return false;
        }
    
        /**
         * @Description 释放锁
         * @Author Chongwen.jiang
         * @Date 2019/9/10 9:54
         * @ModifyDate 2019/9/10 9:54
         * @Params [key]
         * @Return java.lang.Boolean
         */
        public Boolean unLock(Object key) {
            return remove(key);
        }
    
    }
    
    
    

    测试一下:

    @Autowired
        private RedisLock redisLock;
        @Test
        public void testRedisLock(){
            String key = "aaaa";
            try {
                Boolean locked = redisLock.lock(key, 1000L, 1000*60L);
                if(locked) {
                    System.out.println("获取锁成功,开始执行业务代码...");
    
                    Thread.sleep(1000*10);
    
                } else {
                    System.out.println("获取锁失败...");
    
                }
            } catch (Exception e) {
                log.error(e.getMessage());
                e.printStackTrace();
            } finally {
                log.info("释放锁:{}", redisLock.unLock(key));
            }
    
        }
    
    

    2、Redisson高性能分布式锁代码实现(AOP实现)

    在一些高并发的场景中,比如秒杀,抢票,抢购这些场景,都存在对核心资源,商品库存的争夺,控制不好,库存数量可能被减少到负数,出现超卖的情况,或者 产生唯一的一个递增ID,由于web应用部署在多个机器上,简单的同步加锁是无法实现的,给数据库加锁的话,对于高并发,1000/s的并发,数据库可能由行锁变成表锁,性能下降会厉害。那相对而言,redis的分布式锁,相对而言,是个很好的选择,redis官方推荐使用的Redisson就提供了分布式锁和相关服务。

    添加maven依赖

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.2</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    <dependency>
        <groupId>org.redisson</groupId>
        <artifactId>redisson</artifactId>
        <version>3.5.5</version>
    </dependency>
    
    

    RedissionConfig配置类:

    这里使用的是单机连接模式,redisson提供了单机、主从、哨兵、集群等多种连接方式,感兴趣的可以自行从官网了解学习

    // Copyright 2016-2101 Pica.
    package com.pica.cloud.commercialization.crrs.config;
    
    import io.netty.channel.nio.NioEventLoopGroup;
    import lombok.Data;
    import lombok.extern.slf4j.Slf4j;
    import org.redisson.Redisson;
    import org.redisson.api.RedissonClient;
    import org.redisson.client.codec.Codec;
    import org.redisson.config.Config;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.util.ClassUtils;
    
    /**
     * @ClassName RedissionConfig
     * @Description
     * @Author Chongwen.jiang
     * @Date 2019/9/6 10:40
     * @ModifyDate 2019/9/6 10:40
     * @Version 1.0
     */
    @Slf4j
    @Data
    @Configuration
    public class RedissonConfig {
        private String address = "redis://192.168.110.241:6380";
        private int connectionMinimumIdleSize = 10;
        private int idleConnectionTimeout = 10000;
        private int pingTimeout = 1000;
        private int connectTimeout = 10000;
        private int timeout = 3000;
        private int retryAttempts = 3;
        private int retryInterval = 1500;
        private int reconnectionTimeout = 3000;
        private int failedAttempts = 3;
        private String password = null;
        private int subscriptionsPerConnection = 5;
        private String clientName = null;
        private int subscriptionConnectionMinimumIdleSize = 1;
        private int subscriptionConnectionPoolSize = 50;
        private int connectionPoolSize = 64;
        private int database = 0;
        private boolean dnsMonitoring = false;
        private int dnsMonitoringInterval = 5000;
    
        /**
         * 当前处理核数量 * 2
         */
        private int thread = 2;
    
        /** redisson默认使用的序列化编码类 */
        //private String codec = "org.redisson.codec.JsonJacksonCodec";
        private String codec = "org.redisson.codec.FstCodec";
    
        /**
         * @Description redisson单机连接模式
         * @Author Chongwen.jiang
         * @Date 2019/9/10 12:53
         * @ModifyDate 2019/9/10 12:53
         * @Params []
         * @Return org.redisson.api.RedissonClient
         */
        @Bean(destroyMethod = "shutdown")
        RedissonClient redisson() throws Exception {
            log.info("redission init......");
            Config config = new Config();
            config.useSingleServer().setAddress(address)
                    .setConnectionMinimumIdleSize(connectionMinimumIdleSize)
                    .setConnectionPoolSize(connectionPoolSize)
                    .setDatabase(database)
                    .setDnsMonitoring(dnsMonitoring)
                    .setDnsMonitoringInterval(dnsMonitoringInterval)
                    .setSubscriptionConnectionMinimumIdleSize(subscriptionConnectionMinimumIdleSize)
                    .setSubscriptionConnectionPoolSize(subscriptionConnectionPoolSize)
                    .setSubscriptionsPerConnection(subscriptionsPerConnection)
                    .setClientName(clientName)
                    .setFailedAttempts(failedAttempts)
                    .setRetryAttempts(retryAttempts)
                    .setRetryInterval(retryInterval)
                    .setReconnectionTimeout(reconnectionTimeout)
                    .setTimeout(timeout)
                    .setConnectTimeout(connectTimeout)
                    .setIdleConnectionTimeout(idleConnectionTimeout)
                    .setPingTimeout(pingTimeout)
                    .setPassword(password);
    
            Codec codec = (Codec) ClassUtils.forName(getCodec(),
                    ClassUtils.getDefaultClassLoader()).newInstance();
    
            config.setCodec(codec);
            config.setThreads(thread);
            config.setEventLoopGroup(new NioEventLoopGroup());
            config.setUseLinuxNativeEpoll(false);
            return Redisson.create(config);
        }
    
    }
    
    
    

    这里值得注意的是redisson使用的序列化编码类是org.redisson.codec.JsonJacksonCodec,JsonJackson在序列化有双向引用的对象时,会出现无限循环异常。而fastjson在检查出双向引用后会自动用引用符$ref替换,终止循环。

    如果序列化了一个service,这个service已被spring托管,而且和另一个service之间也相互注入了,用fastjson能 正常序列化到redis,而JsonJackson则抛出无限循环异常。

    为了序列化后的内容可见,所以使用FstCodec(org.redisson.codec.FstCodec)
    在这里插入图片描述

    定义注解类

    package com.pica.cloud.commercialization.crrs.interceptor;
    
    import java.lang.annotation.*;
    import java.util.concurrent.TimeUnit;
    
    /**
     * @ClassName RLock
     * @Description 分布式锁
     * @Author Chongwen.jiang
     * @Date 2019/9/6 10:47
     * @ModifyDate 2019/9/6 10:47
     * @Version 1.0
     */
    @Target({ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    public @interface Rlock {
    
        /** 分布式锁的key */
        String localKey();
    
        /** 锁释放时间 默认5秒 */
        long leaseTime() default 5 * 1000;
    
        /** 时间格式 默认:毫秒 */
        TimeUnit timeUtil() default TimeUnit.MILLISECONDS;
    
    }
    
    

    注解业务实现类:

    // Copyright 2016-2101 Pica.
    package com.pica.cloud.commercialization.crrs.interceptor;
    
    import com.alibaba.fastjson.JSON;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.commons.codec.binary.Hex;
    import org.apache.commons.lang.StringUtils;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Pointcut;
    import org.aspectj.lang.reflect.MethodSignature;
    import org.redisson.api.RLock;
    import org.redisson.api.RedissonClient;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    import org.springframework.util.CollectionUtils;
    import org.springframework.web.context.request.RequestAttributes;
    import org.springframework.web.context.request.RequestContextHolder;
    import org.springframework.web.context.request.ServletRequestAttributes;
    
    import javax.crypto.Cipher;
    import javax.crypto.KeyGenerator;
    import javax.crypto.SecretKey;
    import javax.crypto.spec.SecretKeySpec;
    import javax.servlet.http.HttpServletRequest;
    import java.security.Key;
    import java.util.Enumeration;
    import java.util.Map;
    import java.util.concurrent.ConcurrentHashMap;
    
    /**
     * @ClassName RlockAspect
     * @Description 分布式锁aop配置
     * @Author Chongwen.jiang
     * @Date 2019/9/6 10:52
     * @ModifyDate 2019/9/6 10:52
     * @Version 1.0
     */
    @Slf4j
    @Aspect
    @Component
    public class RlockAspect {
        @Autowired
        private RedissonClient redissonClient;
    
        ThreadLocal<HttpServletRequest> request = new ThreadLocal();
    
        @Pointcut("@annotation(com.pica.cloud.commercialization.crrs.interceptor.Rlock)")
        public void RlockAspect() {
            log.info("RlockAspect constructor...");
        }
    
    
        @Around("RlockAspect()")
        public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
            String params = getAllRequestParam(proceedingJoinPoint);
    
            Object object = null;
            RLock lock = null;
    
            try {
                Rlock rlockInfo = getRlockInfo(proceedingJoinPoint);
                lock = redissonClient.getLock(getLocalKey(proceedingJoinPoint, rlockInfo, params));
                if (null != lock) {
                    final boolean status = lock.tryLock(rlockInfo.leaseTime(), rlockInfo.timeUtil());
                    if (status) {
                        log.info("获取到锁.....");
                        object = proceedingJoinPoint.proceed();
                    }
                }
            } finally {
                if (lock != null) {
                    log.info("释放锁.....");
                    lock.unlock();
                }
            }
    
            return object;
        }
    
        public Rlock getRlockInfo(ProceedingJoinPoint proceedingJoinPoint) {
            MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
            return methodSignature.getMethod().getAnnotation(Rlock.class);
        }
    
        /**
         * @Description 生成redis lock key
         * @Author Chongwen.jiang
         * @Date 2019/9/6 11:05
         * @ModifyDate 2019/9/6 11:05
         * @Params [proceedingJoinPoint, rlockInfo]
         * @Return java.lang.String
         */
        public String getLocalKey(ProceedingJoinPoint proceedingJoinPoint, Rlock rlockInfo, String params) {
            StringBuffer localKey = new StringBuffer("Rlock");
            //body中的参数
            final Object[] args = proceedingJoinPoint.getArgs();
    
            MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
            //方法名称
            String methodName = methodSignature.getMethod().getName();
    
            //参数加密
            //params = jdkAES(params);
    
            localKey.append(rlockInfo.localKey()).append("-")
                    .append(methodName).append("-")
                    .append(params);
    
            log.info("getLocalKey: {}", localKey.toString());
            return localKey.toString();
        }
    
        /**
         * @Description 获取query、body和header中的所有参数
         * @Author Chongwen.jiang
         * @Date 2019/9/6 13:11
         * @ModifyDate 2019/9/6 13:11
         * @Params [request]
         * @Return java.util.Map<java.lang.String,java.lang.String>
         */
        private String getAllRequestParam(ProceedingJoinPoint proceedingJoinPoint) {
            RequestAttributes ra = RequestContextHolder.getRequestAttributes();
            ServletRequestAttributes sra = (ServletRequestAttributes) ra;
            HttpServletRequest request = sra.getRequest();
            this.request.set(request);
    
            //参数获取
            Map<String, Object> params = new ConcurrentHashMap<>();
    
            params.put("url", request.getRequestURL());
    
            params.put("method", request.getMethod());
    
            Object[] bodyParams = proceedingJoinPoint.getArgs();
            if (null != bodyParams && bodyParams.length > 0) {
                params.put("bodyParams", bodyParams);
            }
    
            String queryParams = request.getQueryString();
            if (StringUtils.isNotEmpty(queryParams)) {
                params.put("queryParams", queryParams);
            }
    
            Map<String, String> headerParams = new ConcurrentHashMap<>();
            Enumeration<?> headers = request.getHeaderNames();
            if (null != headers) {
                while (headers.hasMoreElements()) {
                    String element = (String) headers.nextElement();
                    String value = request.getHeader(element);
                    if ("token".equals(element)) {
                        headerParams.put(element, value);
                    }
                    if (StringUtils.isEmpty(element)) {
                        headerParams.remove(element);
                    }
                }
            }
    
            if (!CollectionUtils.isEmpty(headerParams)) {
                params.put("headerParams", headerParams);
            }
    
            String json = JSON.toJSONString(params);
            log.info("getAllRequestParam: {}", json);
            return json;
        }
    
        /**
         * @Description 使用jdk实现AES加密
         * @Author Chongwen.jiang
         * @Date 2019/9/6 13:48
         * @ModifyDate 2019/9/6 13:48
         * @Params [source]
         * @Return void
         */
        private String jdkAES(String source) {
            try {
                // 生成KEY
                KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
                keyGenerator.init(128);
                // 产生密钥
                SecretKey secretKey = keyGenerator.generateKey();
                // 获取密钥
                byte[] keyBytes = secretKey.getEncoded();
    
                // KEY转换
                Key key = new SecretKeySpec(keyBytes, "AES");
    
                // 加密
                Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
                cipher.init(Cipher.ENCRYPT_MODE, key);
                byte[] result = cipher.doFinal(source.getBytes());
                return Hex.encodeHexString(result);
    
                /*System.out.println("jdk aes encrypt:" + Hex.encodeHexString(result));
                // 解密
                cipher.init(Cipher.DECRYPT_MODE, key);
                result = cipher.doFinal(result);
                System.out.println("jdk aes decrypt:" + new String(result));*/
    
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    
    
    }
    
    
    
    

    controller层使用注解

    @PostMapping("/{id}")
    @Rlock(localKey = "redisLockAnnotion", leaseTime = 10, timeUtil = TimeUnit.SECONDS)
    public ApiResponse<?> order(@RequestParam(required = false) String a, @PathVariable String id) {
        Map<String, Object> resultMap = dictService.doModify();
        return new ApiResponse<>(resultMap);
    }
    
    

    这里我设置的锁释放时间是10秒,所以就需要程序员自己估计业务代码执行时间一定不能超过该时间,否则在释放锁的时候,redisson会抛出异常
    在这里插入图片描述

    测试日志打印如下

    在这里插入图片描述

    简洁实用的Redis分布式锁用法

    展开全文
  • 频率与上升/下降时间简述频率上升/下降时间比较 简述 人们普遍认为在高速系统设计中需要考虑的关键问题是频率,其实这是误解,上升时间才是最关键的因素。 频率 频率是指电流周期的波形在某个单位时间内重复的次数...

    简述

    人们普遍认为在高速系统设计中需要考虑的关键问题是频率,其实这是误解,上升时间才是最关键的因素。

    频率

    频率是指电流周期的波形在某个单位时间内重复的次数(通常是1s),单位通常为赫兹(Hz)。如我国的市电一般为50Hz,即电流在1秒钟重复了50次。如在板级比较常用的SPI协议,50MHz的话则表示它的时钟能在1秒钟重复5000万次(当然实际使用中由于每个指令周期之间会存在一定间隔,所以会小于这个数量),它的信号周期长度为1/f,其中f为频率,所以50MHz SPI的一个时钟周期为五千万分之一秒,即20ns。

    上升/下降时间

    上升时间一般定义为从波形的10%处上升到波形的90%处所需要的时间(也有定义规定从20%处上升到80%处的时间)。下降时间的定义与之相同,即从波形的90%处下降到10%所需要的时间。
    在这里插入图片描述
    正弦波信号的上升时间大约是其周期的1/3。

    我们可以用ΔI/Δt和ΔU/Δt表示某一段时间内电流和电压的变化,如果Δt是一个特变小的时间间隔时,就可以在数学上用dI/dt和dU/dt来表示ΔI/Δt和ΔUt。dI/dt和dU/dt是微分表达式,表示当时间变化为无限小时,电流和电压变化与时间变化之比。在高速电路中,dt可以等于信号的上升或下降时间,正是这个dI/dt和dU/dt引出了信号完整性问题

    比较

    在这里插入图片描述
    可以看出图中虚线的方波和实线的正弦波的频率是相同的,但是方波的上升时间和下降时间要远远小于正弦波的时间。熟悉傅里叶定理的同学应该能知道,方波在自然界中实际是不存在的,但是我们可以利用傅里叶变换,用余弦波或正弦波的无穷序列来表示它。理想50%占空比方波是由无穷的奇次谐波组成

    Square(θ)=cos(θ)cos(3θ)3+cos(5θ)5cos(7θ)7+...Square(\theta) = \cos(\theta) - \frac{\cos(3\theta)}{3} + \frac{\cos(5\theta)}{5} - \frac{\cos(7\theta)}{7} + ...

    如果我们在走线的一端输入方波信号,希望在另一端也得到方波信号,意味着我们所设计的电路板不仅能处理数字信号的基频,还必须能处理信号所包含的全部高次谐波分量。所以如果我们面对的是10MHz的方波,那么我们可能希望能处理15次或者以上的谐波,才能较好的呈现一个方波,那么就意味着我们必须要处理150MHz甚至以上的谐波频率。所以这就是为什么信号的周期频率并不重要,而波形的上升时间和需要重新产生的谐波才是重要的原因。

    我们可以使用带宽这个词来描述上述要求。带宽指的是能够保持信号完整性的频率范围。可以粗略用下式来确定带宽要求

    Hz0.3/带宽(Hz) \approx 0.3/上升时间

    参考文献 《Signal Integrity Issues and Printed Circuit Board Design 》Douglas Brooks

    展开全文
  • 最近研究循环坐标下降(cyclic coordinate decent,CCD)算法,发现它在处理人物的某些关节上不起作用。CCD算法的原始算法针对的是多个骨骼、多个关节的IK解算处理,但是对于人体骨骼有着特殊的构造,使用CCD算法不...

    循环坐标下降(CCD)算法中对骨骼动画中膝盖等关节的特殊处理

             最近研究循环坐标下降(cyclic coordinate decentCCD)算法,发现它在处理人物的某些关节上不起作用。CCD算法的原始算法针对的是多个骨骼、多个关节的IK解算处理,但是对于人体骨骼有着特殊的构造,使用CCD算法不能正确地反映这些构造,所以我们必须对这些构造进行特殊处理。

           那么人体骨骼的构造特殊性在哪儿呢?这里我们暂且不探讨骨骼扭转的情况,仅仅探讨骨骼旋转的情况。我们发现人体的一些部位有三个自由度(3 Dimensions of Freedom3DoF),而另一些部位只有一个自由度(1DoF),比如说我们的肩膀关节,它就有三个自由度,而肘部关节只有一个自由度;同理髋关节(如果可能的话)有三个自由度,而膝关节只有一个自由度。

    了解这些很重要,因为我们要对CCD算法的结果进行进一步的限制。一般来说,普通的骨骼(比如说头发骨骼),当对末端关节进行移动以靠近固定关节时,二维的情况有两个解,三维的情况就有无穷多个解,解集会形成一个圆圈。我们只能看到我们的小腿相对于大腿顺着弯曲,却无法想象小腿相对大腿反着弯曲。这就是必须要限制的原因。

    如果不限制的话,就会出现这样的情况:



    正常情况是这样的:

     

           那么如何对CCD算法进行限制呢?下面以膝盖为例。首先在预处理阶段判断骨骼的关节处是否为膝盖,保存为一个bool值,以后这样的骨骼进行单独处理。处理的方法是这样的:不以向量叉积求出的旋转轴进行旋转,而是以仅仅以X轴进行旋转。下面是改进后的代码:

    /*---------------------------------------------------------------------------*/
    void MMDRenderHandler::CalculateInverseKinematics( void )// 计算反向运动学
    {
        // 遍历每个IK
        foreach ( const IK& _IK, m_IKs )
        {
            Bone& destBone = m_Bones[_IK.destIndex];        // 一般是IK骨骼
            Bone& targetBone = m_Bones[_IK.targetIndex];    // 一般是与IK一端连接的骨骼
    
            for ( int i = 0; i < _IK.iteration; ++i )
            {
                for ( int j = 0; j < _IK.bones.size( ); ++j )
                {
                    quint16 index = _IK.bones[j];
                    Bone& joint = m_Bones[index];
    
                    CCDIKSolve( joint,
                                targetBone,
                                destBone,
                                _IK.limitAngle,
                                i );
    
                    CalculateBonesFinalPos( index );
                }
                if ( qFuzzyIsNull( ( targetBone.finalPos -
                                     destBone.finalPos ).SquareLength( ) ) )
                {
                    break;// 目的达到了,结束迭代
                }
            }
        }
    }
    /*---------------------------------------------------------------------------*/
    void MMDRenderHandler::CCDIKSolve( Bone& joint, // 想象成肘部
                                       Bone& target, // 目标位置
                                       Bone& end, // 末端效应器
                                       float limitAngle,// 单位限制角度
                                       int iterNum )// 迭代次数
    {  
        // 使用循环坐标下降算法(cyclic coordinate decent,CCD)
    
        // 计算在绝对旋转后的连接点和目标位置以及末端效应器的相对位置
        Vector3F absJoint2End = end.finalPos - joint.finalPos;
        Vector3F absJoint2Target = target.finalPos - joint.finalPos;
    
        Quaternion invRotation = joint.absRotation.Conjugate( );// 求出四元数的共轭四元数
    
        // 转为本地坐标系(平移因素在第一阶段已剔除)
        Vector3F localJoint2End = invRotation.RotatedVector( absJoint2End );
        Vector3F localJoint2Target = invRotation.RotatedVector( absJoint2Target );
    
        // 计算应该旋转的角度
        float deltaAngle = acosf( Vector3F::DotProduct(
                                      localJoint2End.Normalized( ),
                                      localJoint2Target.Normalized( ) ) );
    
        if ( std::isnan( deltaAngle ) ||
             qFuzzyIsNull( deltaAngle ) )// 角度计算出错或角度太小(一般是向量太接近)
        {
            return;// 不处理,直接返回
        }
    
        // 限制角度为[-limitAngle, limitAngle]
        deltaAngle = qBound( -limitAngle, deltaAngle, limitAngle );
    
        // 求出旋转轴
        Vector3F rotateAxis = Vector3F::CrossProduct( localJoint2Target,
                                                      localJoint2End );
    
        // 构造旋转四元数
        Quaternion deltaRotation = Quaternion::FromRotation(
                    rotateAxis, deltaAngle );
    
        if ( joint.isXContraint )// 连接点的骨骼是膝盖,则限定仅绕X轴旋转
        {
            float curYaw, curPitch, curRoll;
            float deltaYaw, deltaPitch, deltaRoll;
    
            if ( iterNum == 0 )// 第一次迭代仅仅绕着X轴旋转
            {
                deltaRotation = Quaternion::FromRotation(
                            Vector3F( 1.0f, 0.0f, 0.0f ),
                            fabsf( deltaAngle ) );
            }
            else
            {
                deltaRotation.ToEuler( deltaYaw, deltaPitch, deltaRoll );
                joint.rotation.ToEuler( curYaw, curPitch, curRoll );
    
                if ( std::isnan( deltaYaw ) ||
                     qFuzzyIsNull( deltaYaw ) )// 角度计算出错或角度太小(一般是向量太接近)
                {
                    return;// 不处理,直接返回
                }
    
                // 限制前滚角为[-0.002f - curYaw, M_PI - curYaw]
                deltaYaw = qBound( -0.002f - curYaw, deltaYaw, float( M_PI ) - curYaw );
    
                // 进一步限制
                deltaYaw = qBound( -limitAngle, deltaYaw, limitAngle );
    
                deltaRotation = Quaternion::FromEuler( deltaYaw, 0.0f, 0.0f );
            }
        }
    
        joint.rotation *= deltaRotation;
        joint.absRotation = m_Bones[joint.parent].absRotation * joint.rotation;
    }
    

    演示程序下载地址:这里

    展开全文
  • oracle 大事务的并行恢复导致数据库性能下降--cpu使用率较高处理思路   大型事务的回滚 大型事务的回滚产生非常大的代价,不仅锁定需要的资源 ,并且消耗的CPU和IO,尤其是IO将极为密集。这个时候,希望降低...
  • 在梯度下降算法中,都是围绕以下这个式子展开: 其中在上面的式子中hθ(x)代表,输入为x的时候的其当时θ参数下的输出值,与y相减则是一个相对误差,之后再平方乘以1/2,并且其中 注意到x可以一维变量,也可以是...
  • 梯度下降算法

    千次阅读 2016-08-28 20:56:13
    梯度下降法(gradient descent)是一种最优化算法,通常也称为最速下降法,在机器学习中属于最基础的优化算法。谁发明的没查到,有知道的同学可以告诉我。  在机器学习中要用到梯度下降法,至少也是多个变量以上的...
  • 梯度下降优化算法总结

    万次阅读 多人点赞 2017-07-21 22:44:54
    本次介绍梯度下降优化算法。主要参考资料为一篇综述《An overview of gradient descent optimization algorithms》
  • 图像处理的算法SIFT具有尺度不变

    万次阅读 2016-06-03 21:38:27
    计算keypoint周围的16*16的window中每一个像素的梯度,而且使用高斯下降函数降低远离中心的权重。 在每个4*4的1/16象限中,通过加权梯度值加到直方图8个方向区间中的一个,计算出一个梯度方向直方图。 这样...
  • 递归下降分析法

    千次阅读 2020-03-18 19:25:35
    一、实验目的: 根据某一文法编制调试递归下降分析程序,以便对任意输入的符号串进行分析。...改造文法:消除二义、消除左递归、提取左因子,判断是否为LL(1)文法, 3、递归下降分析法实验设计思想及算...
  • 梯度下降优化算法综述

    万次阅读 多人点赞 2016-09-09 00:21:27
    梯度下降优化算法综述   该文翻译自An overview of gradient descent optimization algorithms。   总所周知,梯度下降算法是机器学习中使用非常广泛的优化算法,也是众多机器学习算法中最常用的优化方法。几乎...
  • 机器学习入门系列04,Gradient Descent(梯度下降法)

    万次阅读 多人点赞 2017-03-27 00:35:45
    什么是梯度下降法?学习速率的引入;如何调整学习速率;Adagrad算法介绍;用泰勒展开式对梯度下降法进行数学理论支持
  • 梯度下降

    千次阅读 2017-05-23 12:34:28
     随机梯度下降算法(stochastic gradient descent)可以看成是mini-batch gradient descent的一个特殊的情形,即在随机梯度下降法中每次仅根据一个样本对模型中的参数进行调整,等价于上述的b=1情况下的mini-batch ...
  • 梯度下降法、牛顿迭代法和坐标下降法  最优化方法是一种数学方法,它是研究在给定约束之下如何寻求某些因素(的量),以使某一(或某些)指标达到最优的一些学科的总称。大部分的机器学习算法的本质都是建立优化模型,...
  • 梯度下降算法分类总结

    千次阅读 2018-08-27 15:41:23
    梯度下降算法分类总结 引言 &nbsp; &nbsp;梯度下降法 (Gradient Descent Algorithm,GD) 是为目标函数J(θ),如代价函数(cost function), 求解全局最小值(Global Minimum)的一种迭代算法。 为什么...
  • 梯度下降法算法总结

    千次阅读 多人点赞 2020-02-25 23:33:55
    文章目录梯度下降(Gradient Descent)什么是梯度下降梯度的概念梯度下降举例梯度下降**(**Gradient Descent)公式**优化动态图演示**梯度下降法介绍1 全梯度下降算法(FG)2 随机梯度下降算法(SG)3 小批量梯度下降...
  • 1. 批量梯度下降算法: (1) 如果数据集比较小,完全可以采用全数据集(Full Batch Learning)的形式,采用全数据有两个好处: a.由全数据集确定的方向能够更好地代表样本总体,从而更准确地朝向极值所在的方向。b....
  • 梯度下降法与经典牛顿下降

    千次阅读 2016-05-07 09:45:44
    梯度下降算法 以函数为例, (1)求梯度; (2)向梯度相反方向移动x, ,其中,r为步长,如果步长足够小,则可以保证每一次迭代都在减少,但可能导致太慢,如果步长太大,则不能保证每一次迭代都减少,也不能保证...
  • FMRI数据分析与处理

    万次阅读 多人点赞 2016-12-21 13:22:23
    近年来,血氧水平依赖磁共振脑功能成像(Blood oxygenation level-dependent functional magnetic resonance imaging, BOLD-fMRI)技术得到极快的发展,除了与扫描硬件、扫描技术的进步有关外,更得力于以图形图像等...
  • 首先,王文川同学为大家介绍了无约束优化问题的定义,并举了简单的例子,说明迭代算法解决该类问题的必要,还讲解了强凸性假设和条件数的概念,为后面算法的收敛做知识铺垫。 然后,王文川同学介绍了通用的下降...
  • 优化算法中的鞍点与梯度下降

    千次阅读 2017-12-25 19:44:10
    摘要:本文将讨论寻找凸路径( convex path )时可能会遇到的不同类型的临界点( critical points),特别是基于梯度下降的简单启发式学习方法,在很多情形下会使你在多项式时间内陷入局部最小值( local minimum )...
  • 梯度下降法与反向传播

    万次阅读 2017-11-09 20:16:02
    梯度下降法与反向传播主要内容:梯度下降法 最优化 梯度下降 反向传播 梯度与偏导 链式法则 直观理解 Sigmoid 例子 1. 梯度下降(Gradient descent)初始权重不要都置为0,可用高斯分布。 随机初始化的目的是使对称...
  • 数字图像处理(Digital Image Processing)是通过计算机对图像进行去除噪声、增强、复原、分割、提取特征等处理的方法和技术。本专栏将以学习笔记形式对数字图像处理的重点基础知识进行总结整理,欢迎大家一起学习交流...
  • 最陡下降法、LMS算法、RLS算法及其对比 1、最陡下降算法公式: 是真实梯度,梯度公式中含有数学期望,不易求得。 LMS算法算法公式: ...LMS算法的独立要求: 要求不同时间的输入信号向量线性独立 4、RLS算法在
  • 最小二乘法以估计值与观测值的差的平方和作为损失函数,极大似然法则是以最大化目标值的似然概率函数为目标函数,从概率统计的角度处理线性回归并在似然概率函数为高斯函数的假设下同最小二乘建立了的联系。...
  • 图像平滑处理-中值滤波

    万次阅读 多人点赞 2018-11-06 15:57:18
    图像滤波:即在尽量保留图像细节特征的条件下对目标图像的噪声进行抑制,是图像预处理中不可缺少的操作,其处理效果的好坏将直接影响到后续图像处理和分析的有效和可靠。 消除图像中的噪声...
  • 线性回归和梯度下降

    千次阅读 2018-07-17 10:20:07
    例如身材的过轻,正常,肥胖,过于肥胖,可以被编码为-1,0,1,2,从而转化为实数进行处理。 - 属性离散,但是无序关系(不可比较) 。例如国籍的中国人,美国人,日本人。我们可以将取值有k种的值转化为k维向量,...
  • 随机梯度下降法介绍及其参数讲解

    万次阅读 2020-09-28 17:19:30
    随机梯度下降法 算法介绍 简单来说,梯度下降就是从山顶找一条最短的路走到山脚最低的地方。但是因为选择方向的原因,我们找到的的最低点可能不是真正的最低点。如图所示,黑线标注的路线所指的方向并不是真正...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 272,954
精华内容 109,181
关键字:

性下降怎么处理