Redis 优惠卷秒杀(二) 异步秒杀、基于Stream的消息队列处理

news2024/11/30 6:53:52

目录

基于Stream的消息队列

Redis优化秒杀

登录头 

改进秒杀业务,调高并发性能

Redis消息队列实现异步秒杀

​编辑基于List结构模拟消息队列 

基于PuSub的消息队列

 ​编辑

  基于Stream的消息队列

Redis消息队列


基于Stream的消息队列

Redis优化秒杀

登录头 

 

改进秒杀业务,调高并发性能


@Service
public class VoucherOrderServiceImpl extends ServiceImpl<VoucherOrderMapper, VoucherOrder> implements IVoucherOrderService {

    @Resource
    private ISeckillVoucherService seckillVoucherService;

    @Resource
    private RedisIdWorker redisIdWorker;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private RedissonClient redissonClient;

    private static final DefaultRedisScript<Long> SECKILL_SCRIPT;
    static {
        SECKILL_SCRIPT = new DefaultRedisScript<>();
        SECKILL_SCRIPT.setLocation(new ClassPathResource("seckill.lua"));
        SECKILL_SCRIPT.setResultType(Long.class);
    }
//    阻塞队列
    private BlockingQueue<VoucherOrder> orederTasks = new ArrayBlockingQueue(1024*1024);
//创建线程池
    private static final ExecutorService SECKILL_ORDER_EXECUTOR = Executors.newSingleThreadExecutor();

    @PostConstruct
    private void init(){
        //TODO 类初始化的时候执行线程池
        SECKILL_ORDER_EXECUTOR.submit(new VocherOrderHandler());

    }
    private class VocherOrderHandler implements Runnable{

        @Override
        public void run() {
            while (true) {
                try {
                    //1.获取队列中的订单信息
                    VoucherOrder voucherOrder = orederTasks.take();
//                    2.创建订单
                    handleVocherOrder(voucherOrder);
                }
                catch (Exception e) {
//                    e.printStackTrace();
                    log.error("处理订单异常" ,e);
                }
            }
        }
    }

    private void handleVocherOrder(VoucherOrder voucherOrder) {
        Long userId = voucherOrder.getUserId();
//        Long userId = UserHolder.getUser().getId();
//        synchronized锁还是有线程问题
//        synchronized(userId.toString().intern()) {//intern返回字符串的规范表示
        //TODO 分布锁
        //TODO 创建锁对象
//        SimpleRedisLock lock = new SimpleRedisLock("order" + userId, stringRedisTemplate);
//        TODO 使用工具Redisson
        RLock lock = redissonClient.getLock("lock:order" + userId);
        //获取锁
        //TODO
        boolean isLock = lock.tryLock();
        if ( !isLock ){
            //获取锁失败,返回错误或重试
            log.error("不允许重复下单");
            return ;

        }
        try {
            //获取代理对象(事务)事务生效
            //TODO 获取锁之后再创建事务
//            IVoucherOrderService proxy = (IVoucherOrderService)AopContext.currentProxy();
            //TODO 事务提交完再释放锁
            proxy.createVoucherOrderTwo(voucherOrder);//事务能够
            //TODO 可以避免事务没提交就释放锁的安全问题
        } finally {
            //释放锁
            lock.unlock();
        }
    }

    private IVoucherOrderService proxy;
    //    TODO
    @Override
    public Result seckillVoucher(Long voucherId) {
        Long userId = UserHolder.getUser().getId();
        //1.执行lua脚本
        Long result = stringRedisTemplate.execute(
                SECKILL_SCRIPT,
                Collections.emptyList(),
                voucherId.toString(), userId.toString());
        //2.判断结果为0
        int r = result.intValue();
        if ( r!=0 ) {
            //2.1不为0,代表没有购买资格
            return Result.fail(r==1?"库存不足":"不能重复下单");

        }
        //TODO 2.2为0, 有购买资格,把下单信息保存到阻塞队列
        long orderId = redisIdWorker.nextId("order");
        //2.3.创建订单
        VoucherOrder voucherOrder = new VoucherOrder();
        //2.3订单di
        voucherOrder.setId(orderId);
        //2.4用户id
//        Long userId = UserHolder.getUser().getId();
        voucherOrder.setUserId(userId);
        //2.5代金卷id
        voucherOrder.setVoucherId(voucherId);
        //TODO 2.6 订单放入堵塞队列
        orederTasks.add(voucherOrder);

        //TODO 3.获取代理对象 创建全局变量其他地方才可以用
         proxy = (IVoucherOrderService)AopContext.currentProxy();

        //7.返回订单
        //TODO 保存阻塞队列

        //3.返回订单id

        return Result.ok(orderId);
    }
  /*  @Override
    public Result seckillVoucher(Long voucherId) {
        //1.查询优惠卷
        SeckillVoucher voucher = seckillVoucherService.getById(voucherId);
        //2.判断秒杀是否开始
        if ( voucher.getBeginTime().isAfter(LocalDateTime.now()) ) {
//            秒杀尚未开始
            return Result.fail ("秒杀尚未开始!");
        }

        //3.判断秒杀是否已经结束
        if ( voucher.getEndTime().isBefore(LocalDateTime.now()) ) {
            return Result.fail ("秒杀已结束!");
        }
        //4.判断库存是否充足
        if ( voucher.getStock()<1 ) {
            //库存不足
            return Result.fail("库存不足");
        }
//        -------
        Long userId = UserHolder.getUser().getId();
//        synchronized锁还是有线程问题
//        synchronized(userId.toString().intern()) {//intern返回字符串的规范表示
        //TODO 分布锁
        //TODO 创建锁对象
//        SimpleRedisLock lock = new SimpleRedisLock("order" + userId, stringRedisTemplate);
//        TODO 使用工具Redisson
        RLock lock = redissonClient.getLock("lock:order" + userId);
        //获取锁
        //TODO
        boolean isLock = lock.tryLock();
        if ( !isLock ){
            //获取锁失败,返回错误或重试
            return Result.fail("不允许重复下单");

        }
        try {
            //获取代理对象(事务)事务生效
            //TODO 获取锁之后再创建事务
            IVoucherOrderService proxy = (IVoucherOrderService)AopContext.currentProxy();
            //TODO 事务提交完再释放锁
            return proxy.createVoucherOrder(voucherId);//事务能够
            //TODO 可以避免事务没提交就释放锁的安全问题
        } finally {
            //释放锁
            lock.unlock();
        }
//
//        }
    }
*/
  @Transactional
  public void createVoucherOrderTwo(VoucherOrder voucherOrder) {
      //TODO 6.一人一单
//      TODO 不是在主线程了,在线程池了
      Long userId = voucherOrder.getUserId();
//        userId.toString()底层代码是创建对象,所以有可能还是不一样的
//        synchronized(userId.toString().intern()) {//intern返回字符串的规范表示


      //TODO 6.1查询订单
      Integer count = query().eq("user_id", userId).eq("voucher_id", voucherOrder.getVoucherId()).count();
      //TODO 6.2判断是否存在
      if ( count > 0 ) {
          //用户已经买过了
          log.error("用户已经买过了一次了");
          return ;
      }


      //5.扣减库存
      boolean sucess = seckillVoucherService.update()
              .setSql("stock = stock-1")//set stock = stock-1
              .gt("stock", "0")//可以解决超卖 where id ?and stock >0
              .eq("voucher_id", voucherOrder.getVoucherId()).update();//
//                .eq("stock",voucher.getStock()).update();//where id ?and stock = ?

      if ( !sucess ) {
          //扣减不足
          log.error("库存不足");
          return ;

      }
      //7.0创建订单
      save(voucherOrder);

  }
    @Transactional//加入事务
    public   Result createVoucherOrder(Long voucherId) {
        //TODO 6.一人一单
        Long userId = UserHolder.getUser().getId();
//        userId.toString()底层代码是创建对象,所以有可能还是不一样的
//        synchronized(userId.toString().intern()) {//intern返回字符串的规范表示


            //TODO 6.1查询订单
            Integer count = query().eq("user_id", userId).eq("voucher_id", voucherId).count();
            //TODO 6.2判断是否存在
            if ( count > 0 ) {
                //用户已经买过了
                return Result.fail("用户已经买过了一次了");
            }


            //5.扣减库存
            boolean sucess = seckillVoucherService.update()
                    .setSql("stock = stock-1")//set stock = stock-1
                    .gt("stock", "0")//可以解决超卖 where id ?and stock >0
                    .eq("voucher_id", voucherId).update();//
//                .eq("stock",voucher.getStock()).update();//where id ?and stock = ?

            if ( !sucess ) {
                //扣减不足
                return Result.fail("库存不足");

            }


            //6.创建订单
            VoucherOrder voucherOrder = new VoucherOrder();
            //6.1订单di
            long orderId = redisIdWorker.nextId("order");
            voucherOrder.setId(orderId);
            //6.2用户id
//        Long userId = UserHolder.getUser().getId();
            voucherOrder.setUserId(userId);
            //6.3代金卷id
            voucherOrder.setVoucherId(voucherId);
            save(voucherOrder);
            //7.返回订单
            return Result.ok(orderId);

    }


}

Redis消息队列实现异步秒杀

基于List结构模拟消息队列 

 

基于PuSub的消息队列

 

 

  基于Stream的消息队列

 

 

Redis消息队列


@Service
public class VoucherOrderServiceImpl extends ServiceImpl<VoucherOrderMapper, VoucherOrder> implements IVoucherOrderService {

    @Resource
    private ISeckillVoucherService seckillVoucherService;

    @Resource
    private RedisIdWorker redisIdWorker;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private RedissonClient redissonClient;

    private static final DefaultRedisScript<Long> SECKILL_SCRIPT;
    static {
        SECKILL_SCRIPT = new DefaultRedisScript<>();
        SECKILL_SCRIPT.setLocation(new ClassPathResource("seckill.lua"));
        SECKILL_SCRIPT.setResultType(Long.class);
    }
//    TODO
//创建线程池
    private static final ExecutorService SECKILL_ORDER_EXECUTOR = Executors.newSingleThreadExecutor();

    @PostConstruct
    private void init(){
        //TODO 类初始化的时候执行线程池
        SECKILL_ORDER_EXECUTOR.submit(new VocherOrderHandler());

    }
    private class VocherOrderHandler implements Runnable{
        String querName = "stream.orders";

        @Override
        public void run() {
            while (true) {
                try {
                    //1.获取消息队列中的订单信息
//                    XREADGROUP GROUP g1 c1 COUNT 1 BLOCK 2000 STREAMS stream.order >
                    List<MapRecord<String, Object, Object>> list = stringRedisTemplate.opsForStream().read(
                            Consumer.from("g1", "c1"),
                            StreamReadOptions.empty().count(1).block(Duration.ofSeconds(2)),
                            StreamOffset.create(querName, ReadOffset.lastConsumed())
                    );
                    //判断消息获取是否成功
                    if ( list == null || list.isEmpty() ) {
                        //2.1如果获取失败,说明没有消息,继续下一次循环
                        continue;

                    }
                    //3.解析消息中的订单信息
                    MapRecord<String, Object, Object> record = list.get(0);
                    Map<Object, Object> value = record.getValue();
                    VoucherOrder voucherOrder = BeanUtil.fillBeanWithMap(value, new VoucherOrder(), true);
                    //4.如果获取成功,可以下单
                    handleVocherOrder(voucherOrder);
                    //ACK确认 SACK stream.orders g1 id
                    stringRedisTemplate.opsForStream().acknowledge(querName,"g1",record.getId());
                }
                catch (Exception e) {
//                    e.printStackTrace();
                    log.error("处理订单异常" ,e);
                    handlePendingList();
                }
            }
        }

        private void handlePendingList() {
            while (true) {
                try {
                    //1.获取pending-list中的订单信息
//                    XREADGROUP GROUP g1 c1 COUNT 1 BLOCK 2000 STREAMS stream.order 0
                    List<MapRecord<String, Object, Object>> list = stringRedisTemplate.opsForStream().read(
                            Consumer.from("g1", "c1"),
                            StreamReadOptions.empty().count(1),
                            StreamOffset.create(querName, ReadOffset.from("0"))
                    );
                    //判断消息获取是否成功
                    if ( list == null || list.isEmpty() ) {
                        //2.1如果获取失败,说明pending-list没有异常消息,结束循环
                        continue;

                    }
                    //3.解析消息中的订单信息
                    MapRecord<String, Object, Object> record = list.get(0);
                    Map<Object, Object> value = record.getValue();
                    VoucherOrder voucherOrder = BeanUtil.fillBeanWithMap(value, new VoucherOrder(), true);
                    //4.如果获取成功,可以下单
                    handleVocherOrder(voucherOrder);
                    //ACK确认 SACK stream.orders g1 id
                    stringRedisTemplate.opsForStream().acknowledge(querName,"g1",record.getId());
                }
                catch (Exception e) {
//                    e.printStackTrace();
                    log.error("处理pending-list订单异常" ,e);
                    try {
                        Thread.sleep(20);
                    }
                    catch (InterruptedException interruptedException) {
                        interruptedException.printStackTrace();
                    }
                }
            }

        }
    }
   /*
    //    阻塞队列
    private BlockingQueue<VoucherOrder> orederTasks = new ArrayBlockingQueue(1024*1024);
    private class VocherOrderHandler implements Runnable{

        @Override
        public void run() {
            while (true) {
                try {
                    //1.获取队列中的订单信息
                    VoucherOrder voucherOrder = orederTasks.take();
//                    2.创建订单
                    handleVocherOrder(voucherOrder);
                }
                catch (Exception e) {
//                    e.printStackTrace();
                    log.error("处理订单异常" ,e);
                }
            }
        }
    }
    */

    private void handleVocherOrder(VoucherOrder voucherOrder) {
        Long userId = voucherOrder.getUserId();
//        Long userId = UserHolder.getUser().getId();
//        synchronized锁还是有线程问题
//        synchronized(userId.toString().intern()) {//intern返回字符串的规范表示
        //TODO 分布锁
        //TODO 创建锁对象
//        SimpleRedisLock lock = new SimpleRedisLock("order" + userId, stringRedisTemplate);
//        TODO 使用工具Redisson
        RLock lock = redissonClient.getLock("lock:order" + userId);
        //获取锁
        //TODO
        boolean isLock = lock.tryLock();
        if ( !isLock ){
            //获取锁失败,返回错误或重试
            log.error("不允许重复下单");
            return ;

        }
        try {
            //获取代理对象(事务)事务生效
            //TODO 获取锁之后再创建事务
//            IVoucherOrderService proxy = (IVoucherOrderService)AopContext.currentProxy();
            //TODO 事务提交完再释放锁
            proxy.createVoucherOrderTwo(voucherOrder);//事务能够
            //TODO 可以避免事务没提交就释放锁的安全问题
        } finally {
            //释放锁
            lock.unlock();
        }
    }

    private IVoucherOrderService proxy;

    //TODO
    @Override
    public Result seckillVoucher(Long voucherId) {
//        获取用户
        Long userId = UserHolder.getUser().getId();
//        获取订单id
        long orderId = redisIdWorker.nextId("order");

        //1.执行lua脚本
        Long result = stringRedisTemplate.execute(
                SECKILL_SCRIPT,
                Collections.emptyList(),
                voucherId.toString(), userId.toString(),String.valueOf(orderId));
        //2.判断结果为0
        int r = result.intValue();
        if ( r!=0 ) {
            //2.1不为0,代表没有购买资格
            return Result.fail(r==1?"库存不足":"不能重复下单");

        }
        //TODO 2.2为0, 有购买资格,把下单信息保存到阻塞队列

        //TODO 3.获取代理对象 创建全局变量其他地方才可以用
        proxy = (IVoucherOrderService)AopContext.currentProxy();

        //7.返回订单
        //TODO 保存阻塞队列

        //3.返回订单id

        return Result.ok(orderId);
    }
    //    TODO
   /* @Override
    public Result seckillVoucher(Long voucherId) {
        Long userId = UserHolder.getUser().getId();
        //1.执行lua脚本
        Long result = stringRedisTemplate.execute(
                SECKILL_SCRIPT,
                Collections.emptyList(),
                voucherId.toString(), userId.toString());
        //2.判断结果为0
        int r = result.intValue();
        if ( r!=0 ) {
            //2.1不为0,代表没有购买资格
            return Result.fail(r==1?"库存不足":"不能重复下单");

        }
        //TODO 2.2为0, 有购买资格,把下单信息保存到阻塞队列
        long orderId = redisIdWorker.nextId("order");
        //2.3.创建订单
        VoucherOrder voucherOrder = new VoucherOrder();
        //2.3订单di
        voucherOrder.setId(orderId);
        //2.4用户id
//        Long userId = UserHolder.getUser().getId();
        voucherOrder.setUserId(userId);
        //2.5代金卷id
        voucherOrder.setVoucherId(voucherId);
        //TODO 2.6 订单放入堵塞队列
        orederTasks.add(voucherOrder);

        //TODO 3.获取代理对象 创建全局变量其他地方才可以用
         proxy = (IVoucherOrderService)AopContext.currentProxy();

        //7.返回订单
        //TODO 保存阻塞队列

        //3.返回订单id

        return Result.ok(orderId);
    }
    */
  /*  @Override
    public Result seckillVoucher(Long voucherId) {
        //1.查询优惠卷
        SeckillVoucher voucher = seckillVoucherService.getById(voucherId);
        //2.判断秒杀是否开始
        if ( voucher.getBeginTime().isAfter(LocalDateTime.now()) ) {
//            秒杀尚未开始
            return Result.fail ("秒杀尚未开始!");
        }

        //3.判断秒杀是否已经结束
        if ( voucher.getEndTime().isBefore(LocalDateTime.now()) ) {
            return Result.fail ("秒杀已结束!");
        }
        //4.判断库存是否充足
        if ( voucher.getStock()<1 ) {
            //库存不足
            return Result.fail("库存不足");
        }
//        -------
        Long userId = UserHolder.getUser().getId();
//        synchronized锁还是有线程问题
//        synchronized(userId.toString().intern()) {//intern返回字符串的规范表示
        //TODO 分布锁
        //TODO 创建锁对象
//        SimpleRedisLock lock = new SimpleRedisLock("order" + userId, stringRedisTemplate);
//        TODO 使用工具Redisson
        RLock lock = redissonClient.getLock("lock:order" + userId);
        //获取锁
        //TODO
        boolean isLock = lock.tryLock();
        if ( !isLock ){
            //获取锁失败,返回错误或重试
            return Result.fail("不允许重复下单");

        }
        try {
            //获取代理对象(事务)事务生效
            //TODO 获取锁之后再创建事务
            IVoucherOrderService proxy = (IVoucherOrderService)AopContext.currentProxy();
            //TODO 事务提交完再释放锁
            return proxy.createVoucherOrder(voucherId);//事务能够
            //TODO 可以避免事务没提交就释放锁的安全问题
        } finally {
            //释放锁
            lock.unlock();
        }
//
//        }
    }
*/
  @Transactional
  public void createVoucherOrderTwo(VoucherOrder voucherOrder) {
      //TODO 6.一人一单
//      TODO 不是在主线程了,在线程池了
      Long userId = voucherOrder.getUserId();
//        userId.toString()底层代码是创建对象,所以有可能还是不一样的
//        synchronized(userId.toString().intern()) {//intern返回字符串的规范表示


      //TODO 6.1查询订单
      Integer count = query().eq("user_id", userId).eq("voucher_id", voucherOrder.getVoucherId()).count();
      //TODO 6.2判断是否存在
      if ( count > 0 ) {
          //用户已经买过了
          log.error("用户已经买过了一次了");
          return ;
      }


      //5.扣减库存
      boolean sucess = seckillVoucherService.update()
              .setSql("stock = stock-1")//set stock = stock-1
              .gt("stock", "0")//可以解决超卖 where id ?and stock >0
              .eq("voucher_id", voucherOrder.getVoucherId()).update();//
//                .eq("stock",voucher.getStock()).update();//where id ?and stock = ?

      if ( !sucess ) {
          //扣减不足
          log.error("库存不足");
          return ;

      }
      //7.0创建订单
      save(voucherOrder);

  }
    @Transactional//加入事务
    public   Result createVoucherOrder(Long voucherId) {
        //TODO 6.一人一单
        Long userId = UserHolder.getUser().getId();
//        userId.toString()底层代码是创建对象,所以有可能还是不一样的
//        synchronized(userId.toString().intern()) {//intern返回字符串的规范表示


            //TODO 6.1查询订单
            Integer count = query().eq("user_id", userId).eq("voucher_id", voucherId).count();
            //TODO 6.2判断是否存在
            if ( count > 0 ) {
                //用户已经买过了
                return Result.fail("用户已经买过了一次了");
            }


            //5.扣减库存
            boolean sucess = seckillVoucherService.update()
                    .setSql("stock = stock-1")//set stock = stock-1
                    .gt("stock", "0")//可以解决超卖 where id ?and stock >0
                    .eq("voucher_id", voucherId).update();//
//                .eq("stock",voucher.getStock()).update();//where id ?and stock = ?

            if ( !sucess ) {
                //扣减不足
                return Result.fail("库存不足");

            }


            //6.创建订单
            VoucherOrder voucherOrder = new VoucherOrder();
            //6.1订单di
            long orderId = redisIdWorker.nextId("order");
            voucherOrder.setId(orderId);
            //6.2用户id
//        Long userId = UserHolder.getUser().getId();
            voucherOrder.setUserId(userId);
            //6.3代金卷id
            voucherOrder.setVoucherId(voucherId);
            save(voucherOrder);
            //7.返回订单
            return Result.ok(orderId);

    }


}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/741183.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

skywalking安装

目录 skywalking部署示意图 server安装 裸机安装 docker单节点安装 docker集群安装 k8s安装 helm安装(官方) k8s yaml安装 动态配置安装 client agent安装 skywalking部署示意图 skywalking ui - web界面管理程序oap server - skywalking服务程序nacos - skywalking集…

数字孪生水务系统可视化管理平台有效缓解城市供水压力

针对传统自来水厂供水水质安全隐患大&#xff0c;运行管理落后等问题&#xff0c;基于数字孪生技术构建全厂三维立体模型,在电脑前就可以掌握全厂管线、设备运行情况,遇到预案中的突发事件还可以给出辅助决策方案。从根本上有效提高水厂运行管理效率,增强对水质变化的应对能力,…

分析shein独立站成功的原因

近年来&#xff0c;Shein独立站在快时尚领域声名鹊起&#xff0c;成为许多时尚消费者的首选网站。面对激烈的竞争&#xff0c;它依然能够站稳脚跟并不断壮大。那么&#xff0c;Shein独立站成功的原因是什么呢&#xff1f; Shein独立站——以消费者为中心的运营模式 Shein独立站…

【Python】Locust持续优化:InfluxDB与Grafana实现数据持久化与可视化分析

在进行性能测试时&#xff0c;我们需要对测试结果进行监控和分析&#xff0c;以便于及时发现问题并进行优化。 Locust在内存中维护了一个时间序列数据结构&#xff0c;用于存储每个事件的统计信息。 这个数据结构允许我们在Charts标签页中查看不同时间点的性能指标&#xff0c…

java中使用HttpRequest发送请求调用自己的接口

(539条消息) java中使用HttpRequest发送请求_java httprequest_thankful_chn的博客-CSDN博客 <dependency><groupId>com.github.kevinsawicki</groupId><artifactId>http-request</artifactId><version>5.6</version></dependenc…

华为云-hcip笔记-网络服务规划

华为云-hcip笔记-网络服务规划 网络服务规划 安全组和网络ACL 网络ACL对子网进行防护&#xff0c;安全组是对ECS进行防护。 对等连接VPC peering 两个vpc之间的网络连接&#xff0c;用户可以使用私有ip地址在两个vpc之间进行通信。 同账号中对等连接自动接受&#xff0c;跨…

【JavaEE】JVM的组成及类加载过程

博主简介&#xff1a;想进大厂的打工人博主主页&#xff1a;xyk:所属专栏: JavaEE初阶 本文我们主要讲解一下面试中常见的问题&#xff0c;如果想深入了解&#xff0c;请看一下《Java虚拟机规范》这本书 目录 文章目录 一、JVM简介 二、JVM整体组成 2.1 运行时数据区组成 2.2…

【LeetCode周赛】2022上半年题目精选集——数学

文章目录 2183. 统计可以被 K 整除的下标对数目⭐⭐⭐⭐⭐思路——数论&#xff08;一个数乘上另一个数x是k的倍数&#xff0c;x最小是多少&#xff1f;&#xff09;代码1——统计每个数的因子代码2——统计k的因子 2245. 转角路径的乘积中最多能有几个尾随零思路&#xff08;因…

探索全球市场:初创品牌海外营销策略解析

​随着全球化进程的不断推进&#xff0c;越来越多的初创品牌意识到海外市场的巨大潜力&#xff0c;并希望能够将自己的品牌推广到更广阔的国际舞台上。然而&#xff0c;对于初创品牌来说&#xff0c;进军海外市场并开展品牌营销是一项具有挑战性的任务。本文Nox聚星将介绍一些初…

百变探影器 - 是一款很多人都在用的剪辑软件

有没有一款剪辑软件&#xff0c;它不仅颜值高&#xff0c;不用花时间学习就会剪&#xff0c;还自带丰富转场、片头片尾、字幕模板呢&#xff1f;那不得不说的就是一款超级能打的国产剪辑软件—百变探影器软件。 Pr这些比较专业的剪辑软件&#xff0c;基本都需要拥有一定的剪辑…

【实验八】多线程

1、完成书上268页习题第7题和实验题第1、2题 &#xff08;1&#xff09;第7题 import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.*;public class RollWords extends JFrame{ static RollWords.MyThread thre…

西门子S7-200西门子200plc以太网配置向导

方案摘要&#xff1a; 西门子 S7200 系列 PLC通过MatrikonOPC实现以太网连接&#xff0c;捷米特ETH-S7200-JM01以太网模块为 PLC200转换出以太网通讯接口。 功能简介 MatrikonOPC是世界上最大的OPC开发商和供应商&#xff0c;我们的产品涵盖了OPC服务器、客户端、应用程序、O…

为D1定义一个f()函数,重做练习1-3,并解释其结果

运行代码&#xff1a; //为D1定义一个f()函数&#xff0c;重做练习1-3,并解释其结果 #include"std_lib_facilities.h" //---------------------------------------------------------------------- //定义B1类。 class B1 { public:virtual void vf() { cout<<…

第四章 数学知识(二)——欧拉函数,快速幂,扩展欧与中国剩余定理

文章目录 欧拉函数线性筛求欧拉函数欧拉定理 快速幂逆元 扩展欧几里得中国剩余定理扩展中国剩余定理 欧拉函数练习题873. 欧拉函数874. 筛法求欧拉函数 快速幂练习题875. 快速幂876. 快速幂求逆元 扩展欧练习题877. 扩展欧几里得算法878. 线性同余方程 中国剩余定理练习题204. …

Linux进程信号(一)

信号产生 1.信号基础知识2.初步认识信号3.signal函数4.技术应用角度的信号5.调用系统函数向进程发信号6.由软件条件产生的信号7.硬件异常产生信号8.core &#x1f31f;&#x1f31f;hello&#xff0c;各位读者大大们你们好呀&#x1f31f;&#x1f31f; &#x1f680;&#x1f…

从CoCo到喜茶,新茶饮品牌领悟出海的“九阴真经”了吗?

炎炎夏日里&#xff0c;一杯冰凉的奶茶和果茶受到了更多追捧。但是&#xff0c;中国新茶饮品牌却站在了一个十字路口。 随着新茶饮迈入“万店时代”&#xff0c;国内市场已经出现了明显的内卷现象&#xff0c;头部品牌之间的竞争日趋激烈&#xff0c;中小品牌的生存空间被挤压…

OpenGL的学习记录(一)(一些基本概念)

1.OpenGL是什么&#xff1f; OpenGL是一组各个GPU厂家一起遵循的约定。 2.GLFW&#xff0c;GLAD分别是什么&#xff1f; GLFW解决系统层面的不同&#xff0c;是我们与系统之间的隔离&#xff0c;如&#xff08;创建窗口&#xff0c;定义上下文&#xff0c;处理用户输入&#x…

数据结构--树和森林的遍历

数据结构–树和森林的遍历 树的先根遍历 void PreOrder(TreeNode* R) {if (R ! NULL){visit(R);while (R还有下一个子树T)PreOrder(T);} }树和二叉树的转化后》 树的先根遍历序列与这棵树相应二叉树的先序序列相同。 \color{red}树的先根遍历序列与这棵树相应二叉树的先序序列相…

txt文本筛选—python操作

需求&#xff1a;若文档中某行最后一列内容为0&#xff0c;则删除该行&#xff0c;否则保留该行内容&#xff0c;并将筛选后的内容保存到新的文本文档中。 # 读取原始txt文件 with open(depth_values.txt, r) as file:lines file.readlines()# 过滤掉第三列内容为0的行 filter…

WIFISKY-7层流控路由器 后台任意命令执行漏洞复现

这个漏洞相当于是两个漏洞的结合&#xff0c;首先是弱口令漏洞 admin/admin 我们成功登录后台之后才能进行任意命令执行漏洞的操作&#xff0c;我们登录之后找到系统维护-系统控制台 然后我们使用命令拼接的操作来实现任意命令执行的操作 ifconfig & cat /etc/passwd