Flink系列文档-(YY05)-Flink编程API-多流算子

news2024/11/26 9:36:54

1 多流连接 connect

  connect连接(DataStream,DataStream→ConnectedStreams)

connect翻译成中文意为连接,可以将两个数据类型一样也可以类型不一样DataStream连接成一个新的ConnectedStreams。需要注意的是,connect方法与union方法不同,虽然调用connect方法将两个流连接成一个新的ConnectedStreams,但是里面的两个流依然是相互独立的,这个方法最大的好处是可以让两个流共享State状态,状态相关的内容在后面章节讲解

   DataStreamSource<String> ds1 = see.fromElements("a", "b", "c", "d");
   DataStreamSource<Integer> ds2 = see.fromElements(1, 2, 3, 4, 5, 6);
   ConnectedStreams<String, Integer> wordAndNumber = ds1.connect(ds2);

对ConnectedStreams调用map方法时需要传入CoMapFunction函数: 

该接口需要指定3个泛型:

  • 第一个输入DataStream的数据类型
  • 第二个输入DataStream的数据类型
  • 返回结果的数据类型。
  • 该接口需要重写两个方法:
  • map1方法,是对第1个流进行map的处理逻辑。
  • map2方法,是对2个流进行map的处理逻辑

这两个方法必须是相同的返回值类型。指定的输出的数据类型一致.

package com.blok;

import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.datastream.ConnectedStreams;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.functions.co.CoMapFunction;

/**
 * @Date: 22.11.8
 * @Author: Hang.Nian.YY
 * @qq: 598196583
 * @Tips: 学大数据 ,到多易教育
 * @Description:
 */
public class _9Base_API_ConnectFunction{
    public static void main(String[] args) throws Exception {

        Configuration conf = new Configuration();
        conf.setInteger("rest.port", 8888);
        StreamExecutionEnvironment see = StreamExecutionEnvironment.createLocalEnvironmentWithWebUI(conf);
        see.setParallelism(1);

        DataStreamSource<String> ds1 = see.fromElements("a", "b", "c", "d");
        DataStreamSource<Integer> ds2 = see.fromElements(1, 2, 3, 4, 5, 6);
        ConnectedStreams<String, Integer> wordAndNumber = ds1.connect(ds2);

        // 针对 ConnectedStreams 以后调用的方法 传入的是 CoXXXFunction函数
        SingleOutputStreamOperator<String> connectMaped = wordAndNumber.map(new CoMapFunction<String, Integer, String>() {
            // 针对字符串 处理的是左边流的数据
            @Override
            public String map1(String value) throws Exception {
                return null;
            }

            // 针对字符串 处理的是右边流的数据
            @Override
            public String map2(Integer value) throws Exception {
                return null;
            }
        });
        
        see.execute("连接算子") ;
    }
}

对ConnectedStreams调用flatMap方法,调用flatMap方法,传入的Function是CoFlatMapFunction;

这个接口要重写两个方法:

  • flatMap1方法,是对第1个流进行flatMap的处理逻辑;
  • flatMap2方法,是对2个流进行flatMap的处理逻辑;

这两个方法都必须返回是相同的类型。


/**
 * @Date: 22.11.8
 * @Author: Hang.Nian.YY
 * @qq: 598196583
 * @Tips: 学大数据 ,到多易教育
 * @Description:
 */
public class _9Base_API_ConnectFunction02 {
    public static void main(String[] args) throws Exception {

        Configuration conf = new Configuration();
        conf.setInteger("rest.port", 8888);
        StreamExecutionEnvironment see = StreamExecutionEnvironment.createLocalEnvironmentWithWebUI(conf);
        see.setParallelism(1);

        DataStreamSource<String> ds1 = see.fromElements("a b c d", "e f g h", "j k l", "o p l a");
        DataStreamSource<String> ds2 = see.fromElements("1 2 3 4 5" , "6 7 8 9 10");
        ConnectedStreams<String, String> connectedStreams = ds1.connect(ds2);


        connectedStreams.flatMap(new CoFlatMapFunction<String, String, String>() {
            @Override
            public void flatMap1(String value, Collector<String> out) throws Exception {
                String[] split = value.split("\\s+");
                for (String word : split) {
                    out.collect(word);
                }
            }

            @Override
            public void flatMap2(String value, Collector<String> out) throws Exception {
                String[] split = value.split("\\s+");
                for (String word : split) {
                    out.collect(word);
                }
            }
        }) ;
        
        see.execute("连接算子") ;
    }
}

2 多流合并 

该方法可以将两个或者多个数据类型一致的DataStream合并成一个DataStream。DataStream<T> union(DataStream<T>… streams)可以看出DataStream的union方法的参数为可变参数,即可以合并两个或多个数据类型一致的DataStream。

下面的例子是使用fromElements生成两个DataStream,一个是基数的,一个是偶数的,然后将两个DataStream合并成一个DataStream。

/**
 * @Date: 22.11.8
 * @Author: Hang.Nian.YY
 * @qq: 598196583
 * @Tips: 学大数据 ,到多易教育
 * @Description:
 */
public class _10Base_API_Union {
    public static void main(String[] args) throws Exception {
        Configuration conf = new Configuration();
        conf.setInteger("rest.port", 8888);
        StreamExecutionEnvironment see = StreamExecutionEnvironment.createLocalEnvironmentWithWebUI(conf);
        see.setParallelism(1);
        DataStreamSource<Integer> odd = see.fromElements(1, 3, 5, 7, 9);
        DataStreamSource<Integer> even = see.fromElements(2, 4, 6, 8, 10);
        // 将两个流合并在一起
        DataStream<Integer> union = odd.union(even);
        union.print("所有的数据: ");

        see.execute("合并union算子");
    }
}

3  分流操作 - 测流输出

以下function函数,支持将特定数据输出到侧流中:凡是process的函数都有测流输出

  1. ProcessFunction
  2. KeyedProcessFunction
  3. CoProcessFunction
  4. KeyedCoProcessFunction
  5. ProcessWindowFunction
  6. ProcessAllWindowFunction
/**
 * @Date: 22.11.8
 * @Author: Hang.Nian.YY
 * @qq: 598196583
 * @Tips: 学大数据 ,到多易教育
 * @Description:
 */
public class _11Base_API_SideOut {
    public static void main(String[] args) throws Exception {
        Configuration conf = new Configuration();
        conf.setInteger("rest.port", 8888);
        StreamExecutionEnvironment see = StreamExecutionEnvironment.createLocalEnvironmentWithWebUI(conf);
        see.setParallelism(1);

        DataStreamSource<YY2> ds = see.fromElements(
                new YY2(1, "DY", "NM_BT", 100),
                new YY2(2, "XY", "NM_BT", 100),
                new YY2(3, "HH", "SD_HZ", 10),
                new YY2(4, "XH", "SD_HZ", 12)
        );

        final OutputTag<YY2> sideOut = new OutputTag<YY2>("not good"){};

        // 使用测流  将不及格的那家伙和优秀的分开
        // process方法支持测流输出
        SingleOutputStreamOperator<YY2> processed = ds.process(new ProcessFunction<YY2, YY2>() {
            @Override
            public void processElement(YY2 value, ProcessFunction<YY2, YY2>.Context ctx, Collector<YY2> out) throws Exception {

                if (value.getScore() < 60) {  // 将指定规则的不及格的用户 输出到测流
                    ctx.output(sideOut, value);
                } else {  // 将及格的用户输出到主流中     [你们本来就不是一个世界的人, 就不应该有交集]
                    out.collect(value);
                }
            }
        });

        DataStream<YY2> sideOutput = processed.getSideOutput(sideOut);
        sideOutput.print("测流输出:-->不优秀的你:") ;
        processed.print("主流数据:-->优秀的你:") ;
        see.execute("连接算子");
    }
}

4 协同分组

两个流按照指定的属性分别分组 ,将分组后的数据放在一起处理

package com.blok;

import org.apache.flink.api.common.functions.CoGroupFunction;
import org.apache.flink.api.common.typeinfo.TypeHint;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.api.java.tuple.Tuple3;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.windowing.assigners.TumblingProcessingTimeWindows;
import org.apache.flink.streaming.api.windowing.time.Time;
import org.apache.flink.util.Collector;

/**
 * @Date: 22.11.8
 * @Author: Hang.Nian.YY
 * @qq: 598196583
 * @Tips: 学大数据 ,到多易教育
 * @Description: coGroup   协同分组
 * 将两个流按照特定的规则进行分组 , 两个流相同的组数据关联
 */
public class _12Base_API_Cogroup {
    public static void main(String[] args) throws Exception {
        Configuration conf = new Configuration();
        conf.setInteger("rest.port", 8888);
        StreamExecutionEnvironment see = StreamExecutionEnvironment.createLocalEnvironmentWithWebUI(conf);
        see.setParallelism(1);
        /**
         * 1  加载原始数据
         */
        // 输入的数据格式   id,name
        DataStreamSource<String> ds1 = see.socketTextStream("linux01", 8899);
        // 输入的数据格式是  id,event,city
        DataStreamSource<String> ds2 = see.socketTextStream("linux01", 9988);

        /**
         * 2 处理加载的数据成元组
         */
        //id,name
        SingleOutputStreamOperator<Tuple2<String, String>> users = ds1.map(line -> {
            String[] arr = line.split(",");
            return Tuple2.of(arr[0], arr[1]);
        }).returns(new TypeHint<Tuple2<String, String>>() {
        });

        // id,event,city
        SingleOutputStreamOperator<Tuple3<String, String, String>> events = ds2.map(line -> {
            String[] arr = line.split(",");
            return Tuple3.of(arr[0], arr[1], arr[2]);
        }).returns(new TypeHint<Tuple3<String, String, String>>() {
        });

        //利用coGroup算子,来实现两个流的数据按id相等进行窗口关联(包含inner ,left, right, outer)
        DataStream<String> res = users.coGroup(events)
                .where(tp -> tp.f0)
                .equalTo(tp -> tp.f0)
                .window(TumblingProcessingTimeWindows.of(Time.seconds(10)))
                //只要在窗口函数之后才有apply算子
                .apply(new CoGroupFunction<Tuple2<String, String>, Tuple3<String, String, String>, String>() {
                    @Override
                    public void coGroup(Iterable<Tuple2<String, String>> users, Iterable<Tuple3<String, String, String>> events, Collector<String> out) throws Exception {

                        /**
                         * 实现 left  join
                         */
                        for (Tuple2<String, String> user : users) {
                            boolean flag = false;
                            for (Tuple3<String, String, String> event : events) {
                                out.collect(user.f0 + "," + user.f1 + "," + event.f0 + "," + event.f1 + "," + event.f2);
                                flag = true;
                            }
                            //说明没有事件
                            if (!flag) {
                                out.collect(user.f0 + "," + user.f1 + ",null,null,null");
                            }
                        }

                    }
                });
        res.print("left_join") ;
        see.execute() ;


    }
}

5 join算子 

用于关联两个流(类似于sql中join) , 需要指定join的条件;需要在窗口中进行关联后的逻辑计算;

package com.blok;

import org.apache.flink.api.common.functions.CoGroupFunction;
import org.apache.flink.api.common.functions.JoinFunction;
import org.apache.flink.api.common.typeinfo.TypeHint;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.api.java.tuple.Tuple3;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.windowing.assigners.TumblingProcessingTimeWindows;
import org.apache.flink.streaming.api.windowing.time.Time;
import org.apache.flink.util.Collector;

/**
 * @Date: 22.11.8
 * @Author: Hang.Nian.YY
 * @qq: 598196583
 * @Tips: 学大数据 ,到多易教育
 * @Description: join   两个流进行关联
 */
public class _13Base_API_Join {
    public static void main(String[] args) throws Exception {
        Configuration conf = new Configuration();
        conf.setInteger("rest.port", 8888);
        StreamExecutionEnvironment see = StreamExecutionEnvironment.createLocalEnvironmentWithWebUI(conf);
        see.setParallelism(1);
        /**
         * 1  加载原始数据
         */
        // 输入的数据格式   id,name
        DataStreamSource<String> ds1 = see.socketTextStream("linux01", 8899);
        // 输入的数据格式是  id,event,city
        DataStreamSource<String> ds2 = see.socketTextStream("linux01", 9988);

        /**
         * 2 处理加载的数据成元组
         */
        //id,name
        SingleOutputStreamOperator<Tuple2<String, String>> users = ds1.map(line -> {
            String[] arr = line.split(",");
            return Tuple2.of(arr[0], arr[1]);
        }).returns(new TypeHint<Tuple2<String, String>>() {
        });

        // id,event,city
        SingleOutputStreamOperator<Tuple3<String, String, String>> events = ds2.map(line -> {
            String[] arr = line.split(",");
            return Tuple3.of(arr[0], arr[1], arr[2]);
        }).returns(new TypeHint<Tuple3<String, String, String>>() {
        });
        /**
         * 使用join算子将两个数据流关联在一起
         */

        DataStream<String> res = users.join(events)
                .where(tp -> tp.f0)
                .equalTo(tp -> tp.f0)
                .window(TumblingProcessingTimeWindows.of(Time.seconds(20))) // 划分处理数据的窗口
                .apply(new JoinFunction<Tuple2<String, String>, Tuple3<String, String, String>, String>() {
                    @Override
                    public String join(Tuple2<String, String> t1, Tuple3<String, String, String> t2) throws Exception {
                        return t1.f0 + "," + t1.f1 + "," + t2.f0 + "," + t2.f1 + "," + t2.f2;
                    }
                });
        res.print("join-res: ") ;
        see.execute() ;


    }
}

只有同一个窗口中的数据才会触发相对应的数据关联计算 

代码中设置不同的窗口类型  ,触发不同的计算时机

// 滚动窗口
// .window(TumblingProcessingTimeWindows.of(Time.seconds(20))) // 划分处理数据的窗口
// .window(TumblingProcessingTimeWindows.of(Time.seconds(30) , Time.seconds(10)))
// 滑动窗口
.window(SlidingProcessingTimeWindows.of(Time.seconds(30), Time.seconds(10)))
//会话窗口
// .window(ProcessingTimeSessionWindows.withGap(Time.seconds(30)))
  • tumbling window  滚动

  DataStream<String> res = users.join(events)
                .where(tp -> tp.f0)
                .equalTo(tp -> tp.f0)
                // 滚动窗口
                // .window(TumblingProcessingTimeWindows.of(Time.seconds(20))) // 划分处理数据的窗口
                .apply(new JoinFunction<Tuple2<String, String>, Tuple3<String, String, String>, String>() {
                    @Override
                    public String join(Tuple2<String, String> t1, Tuple3<String, String, String> t2) throws Exception {
                        return t1.f0 + "," + t1.f1 + "," + t2.f0 + "," + t2.f1 + "," + t2.f2;
                    }
                });

  • sliding window滑动

  DataStream<String> res = users.join(events)
                .where(tp -> tp.f0)
                .equalTo(tp -> tp.f0)
 
                // 滑动窗口
                .window(SlidingProcessingTimeWindows.of(Time.seconds(30), Time.seconds(10)))
               
                .apply(new JoinFunction<Tuple2<String, String>, Tuple3<String, String, String>, String>() {
                    @Override
                    public String join(Tuple2<String, String> t1, Tuple3<String, String, String> t2) throws Exception {
                        return t1.f0 + "," + t1.f1 + "," + t2.f0 + "," + t2.f1 + "," + t2.f2;
                    }
                });
  • session window 会话

  DataStream<String> res = users.join(events)
                .where(tp -> tp.f0)
                .equalTo(tp -> tp.f0)
                //会话窗口
                // .window(ProcessingTimeSessionWindows.withGap(Time.seconds(30)))

                .apply(new JoinFunction<Tuple2<String, String>, Tuple3<String, String, String>, String>() {
                    @Override
                    public String join(Tuple2<String, String> t1, Tuple3<String, String, String> t2) throws Exception {
                        return t1.f0 + "," + t1.f1 + "," + t2.f0 + "," + t2.f1 + "," + t2.f2;
                    }
                });

 6 广播流

Broadcast State 是 Flink 1.5 引入的新特性。

在开发过程中,如果遇到需要下发/广播配置、规则等低吞吐事件流到下游所有task 时,就可以使用 Broadcast State 特性。下游的 task 接收这些配置、规则并保存为 BroadcastState, 将这些配置应用到另一个数据流的计算中 。

  API 介绍  , 核心要点

  1. 将需要广播出去的流,调用broadcast方法进行广播转换,得到广播流BroadCastStream
  2. 然后在主流上调用connect算子,来连接广播流(以实现广播状态的共享处理)
  3. 在连接流上调用process算子,就会在同一个ProcessFunciton中提供两个方法分别对两个流进行处理,并在这个ProcessFunction内实现“广播状态”的共享
package com.blok;

import org.apache.flink.api.common.functions.JoinFunction;
import org.apache.flink.api.common.state.BroadcastState;
import org.apache.flink.api.common.state.MapStateDescriptor;
import org.apache.flink.api.common.state.ReadOnlyBroadcastState;
import org.apache.flink.api.common.typeinfo.TypeHint;
import org.apache.flink.api.common.typeinfo.TypeInformation;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.api.java.tuple.Tuple3;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.datastream.*;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.functions.co.BroadcastProcessFunction;
import org.apache.flink.streaming.api.windowing.assigners.SlidingProcessingTimeWindows;
import org.apache.flink.streaming.api.windowing.time.Time;
import org.apache.flink.util.Collector;

import javax.swing.*;

/**
 * @Date: 22.11.8
 * @Author: Hang.Nian.YY
 * @qq: 598196583
 * @Tips: 学大数据 ,到多易教育
 * @Description: join   两个流进行关联
 */
public class _14Base_API_BroadCast {
    public static void main(String[] args) throws Exception {
        Configuration conf = new Configuration();
        conf.setInteger("rest.port", 8888);
        StreamExecutionEnvironment see = StreamExecutionEnvironment.createLocalEnvironmentWithWebUI(conf);
        see.setParallelism(1);
        /**
         * 1  加载原始数据
         */
        // 输入的数据格式   id,name
        DataStreamSource<String> ds1 = see.socketTextStream("linux01", 8899);
        // 输入的数据格式是  id,event,city
        DataStreamSource<String> ds2 = see.socketTextStream("linux01", 9988);
        /**
         * 2 处理加载的数据成元组
         */

        //id,event
        SingleOutputStreamOperator<Tuple2<String, String>> events = ds1.map(line -> {
            String[] arr = line.split(",");
            return Tuple2.of(arr[0], arr[1]);
        }).returns(new TypeHint<Tuple2<String, String>>() {
        });

        // id,name,city
        SingleOutputStreamOperator<Tuple3<String, String, String>> users = ds2.map(line -> {
            String[] arr = line.split(",");
            return Tuple3.of(arr[0], arr[1], arr[2]);
        }).returns(new TypeHint<Tuple3<String, String, String>>() {
        });

        /**
         * 示例代码 :
         * 流1  用户行为事件 , 一个用户可能有很多不同的行为事件 出现的时间 出现的次数不确定
         * 流2  用户信息  同一个用户信息数据只会来一次 ,但是来的时间不确定
         *
         * 将用户信息数据 封装成广播流
         */
        //将用户信息数据 封装成广播流
        MapStateDescriptor<String, Tuple2<String, String>> userInfo = new MapStateDescriptor<>("userInfo", TypeInformation.of(String.class), TypeInformation.of(new TypeHint<Tuple2<String, String>>() {}));
        BroadcastStream<Tuple3<String, String, String>> broadcast = users.broadcast(userInfo);

        // 要想使用广播流  , 主流要和广播流进行connect
        BroadcastConnectedStream<Tuple2<String, String>, Tuple3<String, String, String>> connected = events.connect(broadcast);

        // 使用 process方法 处理关联了广播流的连接流数据
        connected.process(new BroadcastProcessFunction<Tuple2<String, String>, Tuple3<String, String, String>, String>() {
            /**
             * 处理主流中的数据
             * @throws Exception
             */
            @Override
            public void processElement(Tuple2<String, String> value, BroadcastProcessFunction<Tuple2<String, String>, Tuple3<String, String, String>, String>.ReadOnlyContext ctx, Collector<String> out) throws Exception {
                // 从上下文对象中 获取广播状态  这个广播状态是只读的
                ReadOnlyBroadcastState<String, Tuple2<String, String>> bc = ctx.getBroadcastState(userInfo);
                if (bc!=null){
                    Tuple2<String, String> user = bc.get(value.f0);
                    if(user!=null){
                        out.collect(value.f0+","+user.f0+","+user.f1+","+value.f1);
                    }else{
                        out.collect(value.f0+",null ,null"+value.f1);
                    }
                }else{  // 广播变量中没有 用户信息
                    out.collect(value.f0+",null ,null"+value.f1);
                }
            }

            /**
             * 操作广播数据  ,将广播数据存储在共享状态中
             * @throws Exception
             */
            @Override
            public void processBroadcastElement(Tuple3<String, String, String> value, BroadcastProcessFunction<Tuple2<String, String>, Tuple3<String, String, String>, String>.Context ctx, Collector<String> out) throws Exception {
                // 从上下文对象中  获取广播状态对象 (可以读写的广播流状态)
                BroadcastState<String, Tuple2<String, String>> bc = ctx.getBroadcastState(userInfo);
                // 将每条广播数据  存储在广播状态中
                bc.put(value.f0, Tuple2.of(value.f1, value.f2));

            }
        });

    }
}

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

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

相关文章

Hadoop高手之路3-Hadoop集群搭建

文章目录Hadoop高手之路3-Hadoop集群搭建一、集群的规划二、再准备两台虚拟机作为服务器1. 根据hadoop001克隆出hadoop002和hadoop0032. 配置hadoop002和hadoop0031) 启动hadoop002虚拟机并登录2) 配置ip地址3) 重启网络服务器&#xff0c;查看ip4) 远程连接hadoop0025) 修改主…

数据库自增ID用完了会怎么样?

有主键 如果设置了主键&#xff0c;并且一般会把主键设置成自增。 Mysql里int类型是4个字节&#xff0c;如果有符号位的话就是[-231,231-1]&#xff0c;无符号位的话最大值就是2^32-1&#xff0c;也就是4294967295。 创建一张表&#xff1a; CREATE TABLE test1 (id int(11…

人脸识别技术趋势与发展

人脸辨识 —— 引人入胜 很少有生物辨识技术能像脸部辨识那样激发我们的想象力。 同样&#xff0c;它的到来在 2020 年引发了深刻的担忧和令人惊讶的反应。 脸部辨识的工作原理 脸部辨识是使用脸部辨识或验证人的身份的过程。它根据人的脸部细节捕获、分析和比较模式。 人…

Restful风格的编程

Restful风格的编程1、 Restful简介2、查询用户以及用户详情2.1常用注解2.2查询用户详情3、处理创建请求3.1RequestBody注解3.1.1用途3.1.2语法规范3.2日期类型的处理3.3BindingResult4、用户信息修改与删除4.1用户信息修改4.2案例前端界面后端控制器1、 Restful简介 Restful比…

剑指offer(C++)-JZ69:跳台阶(算法-动态规划)

作者&#xff1a;翟天保Steven 版权声明&#xff1a;著作权归作者所有&#xff0c;商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处 题目描述&#xff1a; 一只青蛙一次可以跳上1级台阶&#xff0c;也可以跳上2级。求该青蛙跳上一个 n 级的台阶总共有多少种跳法&…

【JavaSE】类与对象(上)类是什么?对象是什么?

文章目录面向过程与面向对象认识类和对象创建类类的实例化内存分布注意事项总结面向过程与面向对象 我们说C语言是面向过程的编程语言&#xff0c;而Java是面向对象的编程语言&#xff0c;那究竟什么才是面向过程与面向对象呢&#xff1f;我们举一个例子来帮助大家理解&#x…

PX4飞行测试

文章目录前言一、首次飞行指南飞行入门解锁飞机起飞降落飞行控制/命令辅助飞行任务飞行规划任务设置机体航向设置航点/转弯半径地理围栏故障保护地理围栏地理围栏规划安全点(集结点)创建/定义安全点地形跟随/保持地形跟随地形保持前言 本节包含有关飞行&#xff08;完全配置过…

虚拟主播也带货?直播电商的变与不变

5月6日晚&#xff0c;海外虚拟主播vox在B站开启了中国直播首秀。从最终数据来看&#xff0c;直播1.7小时&#xff0c;营收111万人民币&#xff0c;当晚还登上平台热门首位&#xff0c;这样的直播吸金能力&#xff0c;让不少明星都望尘莫及。 更值得关注的是&#xff0c;直播间…

Matlab:表达式

Matlab&#xff1a;表达式变量数字矩阵运算符数组运算符函数表达式示例变量 与大多数其他编程语言一样&#xff0c;MATLAB 语言提供数学表达式&#xff0c;但与大多数编程语言不同的是&#xff0c;这些表达式涉及整个矩阵。 MATLAB 不需要任何类型声明或维度说明。当 MATLAB …

PyCharm 这40个使用技巧真棒

大家好&#xff0c;今天分享 PyCharm 40个使用技巧&#xff0c;内容有点长&#xff0c;喜欢欢迎收藏、分享、点赞。 废话不多说。我们开始吧&#xff01; 文章目录技术提升第一章&#xff1a;运行调试篇1\. 通过指定参数&#xff0c;执行程序2\. 程序结束了&#xff0c;照样可…

Vue 3 属性绑定细节

在ButtonDemo中默认会把传给这个组件上的所有事件,都传递给Button中的最外层的元素 不管这个最外层的元素是什么!比如下图:在button外面还有一个div,那么传递给最外层的就应该是div,而不是button 最外层为div 想让组件的某一个部分,点击时被触发click事件 现在传递给最…

LeetCode-764. 最大加号标志【动态规划,二维数组】

LeetCode-764. 最大加号标志【动态规划&#xff0c;二维数组】题目描述&#xff1a;解题思路一&#xff1a;动态规划。用一个n*n的数组记录每个点上下左右方向上为1的最小值。最后ans返回数组中最大的加号。解题思路二&#xff1a;优化1。解题思路三&#xff1a;0题目描述&…

word制作多个单位联合发文的文件头

一、前言 word制作多个单位联合发文的文件头&#xff0c;好像不难。但是做起来&#xff0c;却发现&#xff0c;自己的只是储备还是不够&#xff0c;居然花费了1个多小时才搞定....哎 二、遇到问题 开始思路是想使用【分栏】来操作&#xff0c;但是不得其法&#xff0c;搞了一…

驱动开发基础知识

文章目录记录驱动开发前的知识储备工作一、驱动开发环境搭建二、驱动开发框架&#xff08;重点&#xff1a;WDF框架&#xff09;1、前世今生&#xff08;1&#xff09;Vista简介&#xff08;2&#xff09;发展历史2、基于框架的驱动程序的 WDM&#xff08;1&#xff09;驱动程序…

linux(1.nginx基础 2.使用Nginx负载均衡及动静分离)

一.nginx基础 目录 1. Nginx使用场景2. Nginx中的进程 2.1 Nginx中的多进程模型2.2 多进程模式的优点&#xff1a;2.3 缓存3. Ngnix的负载均衡策略 3.1 轮询法3.2 加权轮询3.3 原地址哈希3.4 最小连接数法3.5 Fair3.6 url_hash3. Nginx配置文件4. Nginxtomcat 集群示例 4.1 下…

c++学习-STL常用函数

第八部分-STL常用函数 5.1 常用遍历算法 5.1.1 for_each 5.1.2 transform 5.2 常用查找算法 5.2.1 find 5.2.2 find_if 5.2.3 adjacent_find 面试题中如果出现查找相邻重复元素&#xff0c;记得用stl中的adjacent_find算法 5.2.4 binary_search 5.2.5 count 5.2.6 count_if 5.…

【双十一特辑】爱心代码(程序员的浪漫)-李峋

前言 最近《点燃我温暖你》中李峋的爱心代码超级火&#xff0c;看着特别心动&#xff0c;这不&#xff0c;光棍节快到了&#xff0c;给兄弟们教学一波爱心代码&#xff0c;赶在双十一前表白&#xff0c;让这个双十一不在是孤单一个人&#xff01;目录 前言 C语言简易爱心代码…

final 关键字 —— 限制继承、限制虚函数重写

final 关键字有两个作用&#xff0c;一个是限制继承&#xff0c;一个是限制重写。 目录 1、限制继承 (1) 基类的构造函数设为私有 (2) 基类类名后面加上 final 关键字修饰 2、限制虚函数重写 1、限制继承 限制继承有两种方式&#xff0c;一种是将基类的构造函数设为私有&am…

谷粒商城-基础篇(详细流程梳理+代码)

文章目录前言一、项目环境搭建1.1、安装virtualbox以及vagrant1.2、Docker安装MySQL与Redis1.3、前后端开发工具统一配置1.4、Git工具安装与配置1.5、Gitee创建仓库与IDEA导入1.6、构建微服务模块1.7、编写.gitignore文件&#xff08;忽略上传gitee文件配置&#xff09;1.8、数…

【云原生之K8s】 K8s资源控制及探针检查

文章目录一、资源限制1.资源限制的使用2.request资源&#xff08;请求&#xff09;和limit资源&#xff08;约束&#xff09;3.Pod和容器的资源请求和限制4.官方文档示例5.资源限制实操5.1 编写yaml资源配置清单5.2 释放内存&#xff08;node节点&#xff0c;以node1为例&#…