2022黑马Redis跟学笔记.实战篇(七)
2022黑马Redis跟学笔记.实战篇 七
- 4.11.附近的店铺功能
- 4.11.1. GEO数据结构的基本用法
- 1. 附近商户-导入店铺数据到GEO
- 4.11.2. 获取附近的店铺
- 1. 附近商户-实现附近商户功能
- 4.9. 签到功能
- 4.9.1.BitMap原理
- 1. 用户签到-BitMap功能演示
- 4.9.2.实现签到功能
- 4.9.3.实现补签功能
- 4.9.4.统计连续签到天数
- 1. 用户签到-签到统计
- 2. 额外加餐-关于使用bitmap来解决缓存穿透的方案
- 4.10.UV统计
- 4.10.1.UV统计的基本思路
- 4.10.2.HypeLogLog实现统计
这里视频中先讲了4.11
4.11.附近的店铺功能
4.11.1. GEO数据结构的基本用法
GEO就是Geolocation的简写形式,代表地理坐标。Redis在3.2版本中加入了对GEO的支持,允许存储地理坐标信息,帮助我们根据经纬度来检索数据。常见的命令有:
- GEOADD:添加一个地理空间信息,包含:经度(longitude)、纬度(latitude)、值(member)
- GEODIST:计算指定的两个点之间的距离并返回
- GEOHASH:将指定member的坐标转为hash字符串形式并返回
- GEOPOS:返回指定member的坐标
- GEORADIUS:指定圆心、半径,找到该圆内包含的所有member,并按照与圆心之间的距离排序后返回。6.以后已废弃
- GEOSEARCH:在指定范围内搜索member,并按照与指定点之间的距离排序后返回。范围可以是圆形或矩形。6.2.新功能
- GEOSEARCHSTORE:与GEOSEARCH功能一致,不过可以把结果存储到一个指定的key。 6.2.新功能。
GEOADD g1 116.378248 39.865275 beijingnan
GEOADD g1 116.42803 39.903738 beijingzhan 116.322287 39.893729 beijingxizhan
看一下图形界面,底层是sortedset
计算距离,以km为单位
GEODIST g1 beijingnan beijingxizhan km
GEODIST g1 beijingxizhan beijingzhan km
天安门附近火车站
GEOSEARCH g1 FROMLONLAT 116.397904 39.909005 BYRADIUS 10 km WITHDIST
再看一下其它指令
- GEOPOS 返回指定memeber的坐标
GEOPOS g1 beijingzhan
- GEOHASH 将指定member的坐标转为hash字符串形式并返回
GEOHASH g1 beijingzhan
1. 附近商户-导入店铺数据到GEO
具体场景说明:
当我们点击美食之后,会出现一系列的商家,商家中可以按照多种排序方式,我们此时关注的是距离,这个地方就需要使用到我们的GEO,向后台传入当前app收集的地址(我们此处是写死的) ,以当前坐标作为圆心,同时绑定相同的店家类型type,以及分页信息,把这几个条件传入后台,后台查询出对应的数据再返回。
我们要做的事情是:将数据库表中的数据导入到redis中去,redis中的GEO,GEO在redis中就一个menber和一个经纬度,我们把x和y轴传入到redis做的经纬度位置去,但我们不能把所有的数据都放入到menber中去,毕竟作为redis是一个内存级数据库,如果存海量数据,redis还是力不从心,所以我们在这个地方存储他的id即可。
但是这个时候还有一个问题,就是在redis中并没有存储type,所以我们无法根据type来对数据进行筛选,所以我们可以按照商户类型做分组,类型相同的商户作为同一组,以typeId为key存入同一个GEO集合中即可
代码
HmDianPingApplicationTests
@Testvoid loadShopData() {// 1.查询店铺信息List<Shop> list = shopService.list();// 2.把店铺按照typeId分组,typeId一样的分一组Map<Long, List<Shop>> map = list.stream().collect(Collectors.groupingBy(Shop::getTypeId));// 3.分批完成写入RedisSet<Map.Entry<Long, List<Shop>>> entries = map.entrySet();for (Map.Entry<Long, List<Shop>> entry : entries) {// 3.1获取typeIdLong typeId = entry.getKey();// 3.2获取同类型的店铺的集合List<Shop> value = entry.getValue();String key = RedisConstants.SHOP_GEO_KEY + typeId;// 3.3 写入Redis// 方法一:打开shop实体类集合,一条店铺一条店铺添加(比较慢)/*for (Shop shop : value) {stringRedisTemplate.opsForGeo().add(key, new Point(shop.getX(), shop.getY()), shop.getId().toString());}*/// 方法二:locationsList<RedisGeoCommands.GeoLocation<String>> locations = new ArrayList<>(value.size());for (Shop shop : value) {locations.add(new RedisGeoCommands.GeoLocation<>(shop.getId().toString(),new Point(shop.getX(), shop.getY())));}stringRedisTemplate.opsForGeo().add(key, locations);}}
运行单元测试
4.11.2. 获取附近的店铺
1. 附近商户-实现附近商户功能
先安装插件Maven Helper,管理依赖
管理Maven依赖
移除老版本
SpringDataRedis的2.3.9版本并不支持Redis 6.2提供的GEOSEARCH命令,因此我们需要提示其版本,修改自己的POM
第一步:导入pom.xml
<dependency><groupId>org.springframework.data</groupId><artifactId>spring-data-redis</artifactId><version>2.6.2</version>
</dependency>
<dependency><groupId>io.lettuce</groupId><artifactId>lettuce-core</artifactId><version>6.1.6.RELEASE</version>
</dependency>
第二步:
修改ShopController
@GetMapping("/of/type")
public Result queryShopByType(@RequestParam("typeId") Integer typeId,@RequestParam(value = "current", defaultValue = "1") Integer current,@RequestParam(value = "x", required = false) Double x,@RequestParam(value = "y", required = false) Double y
) {return shopService.queryShopByType(typeId, current, x, y);
}
修改接口IShopService.java
/*** @param* @return void* @description //根据商铺类型分页查询商铺信息(加入坐标)* @param: typeId* @param: current* @param: x* @param: y* @date 2023/2/19 1:00* @author wty**/Result queryShopByType(Integer typeId, Integer current, Double x, Double y);
修改实现类ShopServiceImpl
/*** @param* @return void* @description //根据商铺类型分页查询商铺信息(加入坐标)* @param: typeId* @param: current* @param: x* @param: y* @date 2023/2/19 1:00* @author wty**/@Overridepublic Result queryShopByType(Integer typeId, Integer current, Double x, Double y) {// 1.判断是否需要根据坐标查询,如果需要再按照坐标if (null == x || null == y) {// 根据类型分页查询Page<Shop> page = query().eq("type_id", typeId).page(new Page<>(current, SystemConstants.DEFAULT_PAGE_SIZE));// 返回数据return Result.ok(page.getRecords());}// 2.分页参数的计算/*** 当前页的起始数据是第几条*/int from = (current - 1) * SystemConstants.DEFAULT_PAGE_SIZE;/*** 当前页的结束数据是第几条*/int end = current * SystemConstants.DEFAULT_PAGE_SIZE;// 3.查询redis,按照距离排序和分页 结果 shopId ,distance// GEOSEARCH g1 FROMLONLAT 116.397904 39.909005 BYRADIUS 10 km WITHDISTString key = RedisConstants.SHOP_GEO_KEY + typeId;GeoResults<RedisGeoCommands.GeoLocation<String>> results = stringRedisTemplate.opsForGeo().search(key,GeoReference.fromCoordinate(x, y),new Distance(RedisConstants.GEO_DISTANT),RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance().limit(end));// 4.解析shopIdif (null == results) {return Result.ok(Collections.emptyList());}List<GeoResult<RedisGeoCommands.GeoLocation<String>>> list = results.getContent();ArrayList<Long> shopIds = new ArrayList<>(list.size());Map<String, Distance> map = new HashMap<>(list.size());// 4.1 截取从from 到 endlist.stream().skip(from).forEach(result -> {// 4.2获取店铺idString shopIdStr = result.getContent().getName();shopIds.add(Long.valueOf(shopIdStr));// 4.3获取距离Distance distance = result.getDistance();map.put(shopIdStr, distance);});// 5.根据id查询shopString joinStr = StrUtil.join(",", shopIds);List<Shop> shops = query().in("id", shopIds).last("order by field(id," + joinStr + ")").list();for (Shop shop : shops) {shop.setDistance(map.get(shop.getId().toString()).getValue());}// 6.返回return Result.ok(shops);}
重启应用,发现按照距离由近到远排序了
此时滚动往下拉发现报错了
发现IDEA控制台报错了
在ShopServiceImpl.java中增加逻辑
if (list.size() <= from) {return Result.ok(Collections.emptyList());}
再次重启,查看下拉就正常了
4.9. 签到功能
4.9.1.BitMap原理
1. 用户签到-BitMap功能演示
我们针对签到功能完全可以通过mysql来完成,比如说以下这张表
用户一次签到,就是一条记录,假如有1000万用户,平均每人每年签到次数为10次,则这张表一年的数据量为 1亿条
每签到一次需要使用(8 + 8 + 1 + 1 + 3 + 1)共22 字节的内存,一个月则最多需要600多字节
我们如何能够简化一点呢?其实可以考虑小时候一个挺常见的方案,就是小时候,咱们准备一张小小的卡片,你只要签到就打上一个勾,我最后判断你是否签到,其实只需要到小卡片上看一看就知道了。
我们可以采用类似这样的方案来实现我们的签到需求。
我们按月来统计用户签到信息,签到记录为1,未签到则记录为0.
把每一个bit位对应当月的每一天,形成了映射关系。用0和1标示业务状态,这种思路就称为位图(BitMap)。这样我们就用极小的空间,来实现了大量数据的表示
Redis中是利用string类型数据结构实现BitMap,因此最大上限是512M,转换为bit则是 232个bit位。
BitMap的操作命令有:
- SETBIT:向指定位置(offset)存入一个0或1,从0开始
- GETBIT :获取指定位置(offset)的bit值
- BITCOUNT :统计BitMap中值为1的bit位的数量
- BITFIELD :操作(查询、修改、自增)BitMap中bit数组中的指定位置(offset)的值
- BITFIELD_RO :获取BitMap中bit数组,并以十进制形式返回
- BITOP :将多个BitMap的结果做位运算(与 、或、异或)
- BITPOS :查找bit数组中指定范围内第一个0或1出现的位置
需求:实现签到接口,将当前用户当天签到信息保存到Redis中
示例:
SETBIT bm1 0 1
GETBIT bm1 0
SETBIT bm1 1 1
SETBIT bm1 2 1
SETBIT bm1 5 1
SETBIT bm1 6 1
查看redis图形界面中存取的数据,注意勾选二进制
BITCOUNT bm1
从0开始2个bit位,刚好是11,二进制11转换为十进制就是3
BITFIELD bm1 GET u2 0
同理取3位,就是111,转换为10进制就是7
BITFIELD bm1 GET u3 0
查找bit数组中指定范围内第一个0出现的位置
BITPOS bm1 0
思路:我们可以把年和月作为bitMap的key,然后保存到一个bitMap中,每次签到就到对应的位上把数字从0变成1,只要对应是1,就表明说明这一天已经签到了,反之则没有签到。
我们通过接口文档发现,此接口并没有传递任何的参数,没有参数怎么确实是哪一天签到呢?这个很容易,可以通过后台代码直接获取即可,然后到对应的地址上去修改bitMap。
4.9.2.实现签到功能
代码
修改UserController
@PostMapping("/sign")public Result sign(){return userService.sign();}
修改接口IUserService.java
/*** @param* @return com.hmdp.dto.Result* @description //签到* @date 2023/2/19 12:21* @author wty**/Result sign();
修改UserServiceImpl
/*** @param* @return com.hmdp.dto.Result* @description //签到* @date 2023/2/19 12:22* @author wty**/@Overridepublic Result sign() {// 1.获取当前登录用户Long userId = UserHolder.getUser().getId();// 2.获取日期LocalDateTime now = LocalDateTime.now();String keySuffix = now.format(DateTimeFormatter.ofPattern(":yyyyMM"));// 3.拼接keyString key = RedisConstants.USER_SIGN_KEY + userId + keySuffix;// 4.获取今天是本月的第几天int dayOfMonth = now.getDayOfMonth();// 5.写入Redis SETBIT key offset 1stringRedisTemplate.opsForValue().setBit(key, dayOfMonth - 1, true);return Result.ok();}
重启应用测试
打开PostMan,配置路径
http://localhost:8080/api/user/sign
配置token
点击send后的结果
保存在redis中的信息如下:比如今天19号,那就在19位是1
4.9.3.实现补签功能
用命令行给前三天补签
SETBIT sign:1010:202302 0 1
SETBIT sign:1010:202302 1 1
SETBIT sign:1010:202302 2 1
前3天签到
4.9.4.统计连续签到天数
1. 用户签到-签到统计
**问题1:**什么叫做连续签到天数?
从最后一次签到开始向前统计,直到遇到第一次未签到为止,计算总的签到次数,就是连续签到天数。
Java逻辑代码:获得当前这个月的最后一次签到数据,定义一个计数器,然后不停的向前统计,直到获得第一个非0的数字即可,每得到一个非0的数字计数器+1,直到遍历完所有的数据,就可以获得当前月的签到总天数了
**问题2:**如何得到本月到今天为止的所有签到数据?
BITFIELD key GET u[dayOfMonth] 0
假设今天是10号,那么我们就可以从当前月的第一天开始,获得到当前这一天的位数,是10号,那么就是10位,去拿这段时间的数据,就能拿到所有的数据了,那么这10天里边签到了多少次呢?统计有多少个1即可。
问题3:如何从后向前遍历每个bit位?
注意:bitMap返回的数据是10进制,哪假如说返回一个数字8,那么我哪儿知道到底哪些是0,哪些是1呢?我们只需要让得到的10进制数字和1做与运算就可以了,因为1只有遇见1 才是1,其他数字都是0 ,我们把签到结果和1进行与操作,每与一次,就把签到结果向右移动一位,依次内推,我们就能完成逐个遍历的效果了。
需求:实现下面接口,统计当前用户截止当前时间在本月的连续签到天数
有用户有时间我们就可以组织出对应的key,此时就能找到这个用户截止这天的所有签到记录,再根据这套算法,就能统计出来他连续签到的次数了。
代码
UserController
@GetMapping("/sign/count")
public Result signCount(){return userService.signCount();
}
IUserService.java
/*** @param* @return com.hmdp.dto.Result* @description //合计签到总数* @date 2023/2/19 14:33* @author wty**/Result signCount();
UserServiceImpl
/*** @param* @return com.hmdp.dto.Result* @description //合计签到总数* @date 2023/2/19 14:33* @author wty**/@Overridepublic Result signCount() {// 1.获取当前登录用户Long userId = UserHolder.getUser().getId();// 2.获取日期LocalDateTime now = LocalDateTime.now();String keySuffix = now.format(DateTimeFormatter.ofPattern(":yyyyMM"));// 3.拼接keyString key = RedisConstants.USER_SIGN_KEY + userId + keySuffix;// 4.获取今天是本月的第几天int dayOfMonth = now.getDayOfMonth();// 5.获取本月截至今天为止所有的签到记录,返回的是一个十进制的数字// BITFIELD bm1 GET u2 0List<Long> results = stringRedisTemplate.opsForValue().bitField(key, BitFieldSubCommands.create().get(BitFieldSubCommands.BitFieldType.unsigned(dayOfMonth)).valueAt(0));if (null == results || results.isEmpty()) {// 没有任何签到结果return Result.ok(0);}Long num = results.get(0);if (null == num || 0 == num) {return Result.ok(0);}// 6.循环遍历// 计数器int calCount = 0;while (true) {// 7.让这个数字与1做与运算,得到数字的最后一个bit位if ((num & 1) == 0) {// 判断这个bit位是否为0,如果为0说明未签到,结束break;} else {// 如果不为0,说明已签到,计数器 + 1calCount++;}// 把数字(无符号)右移一位,抛弃最后一个bit位,继续下一个bit位num = (num >>> 1);}return Result.ok(calCount);}
重新启动应用
用PosrMan测试,注意这里实现的是截至今天为止的连续签到次数,昨天签到,今天没签,连续签到次数也是0
2. 额外加餐-关于使用bitmap来解决缓存穿透的方案
回顾缓存穿透:
发起了一个数据库不存在的,redis里边也不存在的数据,通常你可以把他看成一个攻击
解决方案:
-
判断id<0
-
如果数据库是空,那么就可以直接往redis里边把这个空数据缓存起来
第一种解决方案:遇到的问题是如果用户访问的是id不存在的数据,则此时就无法生效
第二种解决方案:遇到的问题是:如果是不同的id那就可以防止下次过来直击数据
所以我们如何解决呢?
我们可以将数据库的数据,所对应的id写入到一个list集合中,当用户过来访问的时候,我们直接去判断list中是否包含当前的要查询的数据,如果说用户要查询的id数据并不在list集合中,则直接返回,如果list中包含对应查询的id数据,则说明不是一次缓存穿透数据,则直接放行。
现在的问题是这个主键其实并没有那么短,而是很长的一个 主键
哪怕你单独去提取这个主键,但是在11年左右,淘宝的商品总量就已经超过10亿个
所以如果采用以上方案,这个list也会很大,所以我们可以使用bitmap来减少list的存储空间
我们可以把list数据抽象成一个非常大的bitmap,我们不再使用list,而是将db中的id数据利用哈希思想,比如:
id % bitmap.size = 算出当前这个id对应应该落在bitmap的哪个索引上,然后将这个值从0变成1,然后当用户来查询数据时,此时已经没有了list,让用户用他查询的id去用相同的哈希算法, 算出来当前这个id应当落在bitmap的哪一位,然后判断这一位是0,还是1,如果是0则表明这一位上的数据一定不存在, 采用这种方式来处理,需要重点考虑一个事情,就是误差率,所谓的误差率就是指当发生哈希冲突的时候,产生的误差。
4.10.UV统计
4.10.1.UV统计的基本思路
首先我们搞懂两个概念:
- UV:全称Unique Visitor,也叫独立访客量,是指通过互联网访问、浏览这个网页的自然人。1天内同一个用户多次访问该网站,只记录1次。
- PV:全称Page View,也叫页面访问量或点击量,用户每访问网站的一个页面,记录1次PV,用户多次打开页面,则记录多次PV。往往用来衡量网站的流量。
通常来说UV会比PV大很多,所以衡量同一个网站的访问量,我们需要综合考虑很多因素,所以我们只是单纯的把这两个值作为一个参考值。
UV统计在服务端做会比较麻烦,因为要判断该用户是否已经统计过了,需要将统计过的用户信息保存。但是如果每个访问的用户都保存到Redis中,数据量会非常恐怖,那怎么处理呢?
Hyperloglog(HLL)是从Loglog算法派生的概率算法,用于确定非常大的集合的基数,而不需要存储其所有值。相关算法原理大家可以参考:Hyperloglog算法
Redis中的HLL是基于string结构实现的,单个HLL的内存永远小于16kb,内存占用低的令人发指!作为代价,其测量结果是概率性的,有小于0.81%的误差。不过对于UV统计来说,这完全可以忽略。
示例:
添加5个元素
PFADD hl e1 e2 e3 e4 e5
查询元素的个数
PFCOUNT hl
UV统计,对于相同用户不能统计2次,那么我们插入相同元素看一下。发现计算的个数还是5
4.10.2.HypeLogLog实现统计
查看当前redis内存占用情况:
info memory
当前内存占用情况:2139256
测试思路:我们直接利用单元测试,向HyperLogLog中添加100万条数据,看看内存占用和统计效果如何。
代码如下:
@Testpublic void testHyperLog() {String[] values = new String[1000];int j = 0;for (int i = 0; i < 1000000; i++) {j = i % 1000;values[j] = "user_" + i;if (j == 999) {// 发送到RedisstringRedisTemplate.opsForHyperLogLog().add("hl", values);}}// 统计数量Long count = stringRedisTemplate.opsForHyperLogLog().size("hl");System.out.println("统计的总数是:" + count);}
测试结果:
看一下误差
再看一下内存占用:
目前是2175992
与之前的差值是36736bit
换算成kb是35kb
1百万数据只占了36kb
经过测试:我们会发现它的误差是在允许范围内,并且内存占用极小。
黑马实战篇结束了!
相关文章:
2022黑马Redis跟学笔记.实战篇(七)
2022黑马Redis跟学笔记.实战篇 七4.11.附近的店铺功能4.11.1. GEO数据结构的基本用法1. 附近商户-导入店铺数据到GEO4.11.2. 获取附近的店铺1. 附近商户-实现附近商户功能4.9. 签到功能4.9.1.BitMap原理1. 用户签到-BitMap功能演示4.9.2.实现签到功能4.9.3.实现补签功能4.9.4.统…...
QT mp3音乐播放器实现框架,Qt鼠标事件,网络编程,QSqlite,Json解析,HTTP请求等
QT mp3音乐播放器实现框架,Qt鼠标事件,网络编程,QSqlite,Json解析,HTTP请求等框架搭建UI设计mp3.hmp3.cpp隐藏窗口标题 最大化 最小化 关闭框架搭建 .pro添加 # 网络 添加多媒体 数据库 QT network multimedia sql添加头…...
硬件学习 软件Cadence day04 PCB 封装绘制
1.文章内容: 1. 贴片式电容 PCB 封装绘制 (型号 c0603 ) 2. 贴片式电阻 PCB 封装绘制 (型号 r0603 ) 3. 安规式电容 PCB 封装绘制 (这个就是 有一个电容,插入一个搞好的孔里面 …...
【Java】yield()和join()区别
一、java 线程调度的背景 java虚拟机要求在多线程中实现 preemptive和priority-based调度,这意味着java中每一个线程被分配了特定的优先级,正整数在定义好的范围内不断减。优先级可以通过开发者改变但是java虚拟机从不改变线程的优先级,即使…...
【MySQL】Java连接MySQL数据库(封装版只需会MySQL)
一、准备普通项目如果创建的是普通的Java项目,我们需要去maven仓库下载jdbc驱动包然导入项目中就能使用,具体步骤详见MySQL数据库之Java中如何使用数据库【JDBC编程】maven项目如果创建的项目是maven项目,我们只需在pom.xml文件里引入一组依赖…...
【java基础】运算符
运算符 operator 运算符优先级 Operators 操作员Precedence 优先级postfix 后缀expr expr--unary 一元的expr --expr expr -expr ~ !multiplicative 〔数〕乘法的 / %additive 添加剂 -shift 移动<< >> >>>relational 关系的< > < > insta…...
带噪学习-概述
在实际应用的时候,我们的样本不会是完全干净的,即存在噪声样本。那使用存在噪声的样本时,我们如何更有效的进行模型学习呢?Label Dependent Nose样本选择(Sample Selection)第一种很直接的想法,…...
Scratch少儿编程案例-多彩打地鼠
专栏分享 点击跳转=>Unity3D特效百例点击跳转=>案例项目实战源码点击跳转=>游戏脚本-辅助自动化点击跳转=>Android控件全解手册点击跳转=>Scratch编程案例👉关于作者...
为什么拔掉计算机网线还能ping通127.0.0.1?
前言 当我们在计算机上拔掉网线之后,发现我们仍然可以使用ping命令来ping通本机的IP地址127.0.0.1,这让很多人感到困惑,认为拔掉网线后计算机就无法与外界通信了,为什么还能ping通本机的IP地址呢? 本文的目的是通过对…...
Android kotlin 内、外部存储根目录及测试(可以实现仿微信未读消息数提示数字)
<<返回总目录 文章目录 一、内部存储与外部存储三、外部存储的写读测试(可以实现仿微信未读消息数提示数字)一、内部存储与外部存储 所有Android设备都有两个文件存储区域:内部存储空间(internal Storage)和外部存储空间(external Storage)。所以,Android系统从逻…...
Android 7.0 OTA升级(高通)
文章目录1. Full OTA 方式升级介绍1.1 Full OTA 制作第一步:生成 msm89xx-target_files-eng.XXX.zip1.2 Full OTA 制作第二步:Modem 等非 HLOS 加入升级包的方法1.3 Full OTA 制作第三步:生成 update.zip 升级包2. Incremental OTA 方式升级介…...
工作负载之DeployMent
DeployMent 无状态工作负载(Deployment):即kubernetes中的“Deployment”,无状态工作负载支持弹性伸缩与滚动升级,适用于实例完全独立、功能相同的场景,如:nginx、wordpress等。 也是公司中应…...
淘宝tmall页面数据获取,API接口对接程序
item_get-获得淘宝商品详情请求参数请求参数:num_iid652874751412&is_promotion1参数说明:num_iid:淘宝商品IDis_promotion:是否获取取促销价响应参数Version: Date:2022-04-04名称类型必须示例值描述itemitem[]1宝贝详情数据num_iidBigint152081325…...
基于粒子群优化算法的电动汽车充放电V2G研究(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
java并发编程原理2 (AQS, ReentrantLock,线程池)
一、AQS: 1.1 AQS是什么? AQS就是一个抽象队列同步器,abstract queued sychronizer,本质就是一个抽象类。 AQS中有一个核心属性state,其次还有一个双向链表以及一个单项链表。 首先state是基于volatile修饰&#x…...
研报精选230219
目录 【行业230219山西证券】煤炭行业周报:复工改善,港口价格企稳反弹【行业230219中航证券】农林牧渔行业周观点:一号文件落地,生物育种超势不改【行业230219华西证券】汽车行业周报:新车密集上市 自主转型提速【个股…...
【PPPoE】PPPoE拨号流程
简介 PPPoE(Point-to-Point Protocol over Ethernet)是一种在以太网上封装PPP协议的方式,常用于在宽带接入中进行拨号。 PPPoE的拨号原理如下: 客户端发起PPPoE Active Discovery Initiation (PADI)报文,广播到网络…...
django项目实战(django+bootstrap实现增删改查)
目录 一、创建django项目 二、修改默认配置 三、配置数据库连接 四、创建表结构 五、在app当中创建静态文件 六、页面实战-部门管理 1、实现一个部门列表页面 2、实现新增部门页面 3、实现删除部门 4、实现部门编辑功能 七、模版的继承 1、创建模板layout.html 1&…...
Lesson4---Python语言基础(2)
4.1 内置数据结构 4.1.1 序列数据结构(sequence) 成员是有序排列的每个元素的位置称为下标或索引通过索引访问序列中的成员Python中的序列数据类型有字符串、列表、元组 “abc” ≠ “bac” 4.1.1.1 创建列表和元组 Python中的列表和元组,…...
NCHW - NHWC - CHWN 排列
TensorFlow有两种数据格式NHWC和NCHW,默认的数据格式是NHWC,可以通过参数data_format指定数据格式。这个参数规定了 input Tensor 和 output Tensor 的排列方式。 1、data_format 设置为 “NHWC” 时,排列顺序为 [batch, height, width, channels] 设置为 “NCHW” 时,排…...
2019蓝桥杯真题矩阵切割(填空题) C语言/C++
题目描述 本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。 小明有一些矩形的材料,他要从这些矩形材料中切割出一些正方形。 当他面对一块矩形材料时,他总是从中间切割一刀,切出一块最大的正…...
Java线程池的创建以及原理
一、为什么要使用线程池 在外面的日常开发中,也使用了不少池化技术,比如线程池、数据库连接池、HTTP连接池等等都是对这个思想的应用。 池化技术的思想主要是为了减少每次获取资源的消耗,提高对资源的利用率。 线程池提供了一种限制和管理资…...
Java集合学习之Map
1.什么是Map Java里的Map接口是一个集合根接口,表示一个 键值对(Key-Value) 的映射。 简单来说就是键和值是一对的,每一个 Key都有唯一确定的 Value对应。 其中要求 键(Key) 唯一,因为是按照…...
java 基于maven多模块合并打包部署
项目环境 jdk 1.8spring 2.7.xmaven 3.6 项目结构 模块功能 client – 对外service common – 共用工具切面等 main – 启动类 goods – 子模块具体实现 模块间依赖关系 client – 无依赖 common – 无依赖 main – client、common、goods goods – client、common 具体P…...
Kubernetes是个什么东东?
Kubernetes 是一个可移植、可扩展的开源平台,用于管理容器化的工作负载和服务,可促进声明式配置和自动化。 Kubernetes 拥有一个庞大且快速增长的生态,其服务、支持和工具的使用范围相当广泛。 Kubernetes 这个名字源于希腊语,意…...
【go语言grpc之client端源码分析三】
go语言grpc之server端源码分析三newClientStreamnewAttemptLocked上一篇在介绍了grpc.Dial之后,然后再介绍一下后面的 //创建RPC客户端client : pb.NewGreetsClient(conn)//设置超时时间_, cancel : context.WithTimeout(context.Background(), time.Second)defer c…...
Android 基础知识4-2.6LinearLayout(线性布局)
一、LinearLayout的概述 线性布局(LinearLayout)主要以水平或垂直方式来排列界面中的控件。并将控件排列到一条直线上。在线性布局中,如果水平排列,垂直方向上只能放一个控件,如果垂直排列,水平方向上也只能…...
补充前端面试题(三)
图片懒加载<!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"widthdevice-width, in…...
.net开发安卓入门-自动升级(配合.net6 webapi 作为服务端)
文章目录思路客户端权限清单(AndroidManifest.xml)权限列表(完整内容看 权限清单(AndroidManifest.xml))打开外部应用的权限(完整内容看 权限清单(AndroidManifest.xml))添加文件如下…...
分享111个HTML艺术时尚模板,总有一款适合您
分享111个HTML艺术时尚模板,总有一款适合您 111个HTML艺术时尚模板下载链接:https://pan.baidu.com/s/1sYo2IPma4rzeku3yCG7jGw?pwdk8dx 提取码:k8dx Python采集代码下载链接:采集代码.zip - 蓝奏云 时尚理发沙龙服务网站模…...
做网站用到的工具/网站运营一个月多少钱
前几天小组讨论,窗外的麻雀在电线杆上多嘴,想想很有夏天的感觉,手中的铅笔在纸上来了又回,我用几行字形容孰是孰非......... Echarts使用指南 百度网站:http://echarts.baidu.com/ 首先说下该网站上的简介,…...
徐州免费网站建设/空间刷赞网站推广
最近公司申请了华为云的资源做测试。在丢了一个小项目上去测试之后,发现系统CPU异常繁忙,系统重启之后情况依旧,连接服务器异常缓慢。这时也接到华为云的客服电话说测试服务器同***服务器之间有通信,让我们确认是不是正常的情况。…...
网站建设总体需求分析/网站seo哪里做的好
【本周总结】 1.学习了js红宝书的第四章:基本类型和引用类型的值、执行环境、垃圾收集 2.总结了js红宝书前三章内容 3.学习了ps的一些工具:油漆桶工具、橡皮擦工具、修饰工具、选框工具、套索工具、快速选择工具组、直方图和明暗调整、图层和调整图层 4…...
做微信的网站有哪些/千锋教育可靠吗
考虑下面这个“魔力”三角形环,在其中填入1至6这6个数,每条线上的三个数加起来都是9。 从最外侧结点所填的数最小的线(在这个例子中是4,3,2)开始,按顺时针方向,每个解都能被唯一表述。例如,上面…...
网站建设合同内容与结构/网络推广员为什么做不长
#include <stdio.h>int main() { // 定义相乘数字i,j以及结果result int i, j, result; for(i9;i>1;i--) { for(j1;j<i;j) { printf("%d*%d%d ",i,j,resulti*j); } printf("\n"); } return 0;}转载于:https://www.cn…...
网站文案技巧/免费的网站推广在线推广
1.Shell条件测试 1.1.数值比较: 操作符: gt:大于lt:小于eq:等于ne:不等于ge:大于等于le:小于等于 测试语法: 方式1:test 条件表达式 [rootVM-0-17-centos ~…...