14、Kafka ------ kafka 核心API 之 流API(就是把一个主题的消息 导流 到另一个主题里面去)

目录

  • kafka 核心API 之 流API
    • Kafka流API的作用:
    • 流API的核心API:
    • 使用流API编程的大致步骤如下:
    • 代码演示 流API 用法
      • MessageStream 流API 代码
      • 演示消息从 test1主题 导流到 test2主题
      • 演示使用匿名内部类对消息进行处理
      • Topology 拓扑结构 讲解
    • 代码:
      • MessageProducer 消息生产者
      • Consumer01 消费者01
      • Consumer02 消费者02
      • MessageStream 流API 功能演示类
      • pom 依赖

kafka 核心API 之 流API


Kafka流API的作用:

流API 的作用 是创建多个主题之间的消息流,从而允许将消息从一个主题“导流”到另一个主题,在消息“导流”的过程中,客户端程序可对消息进行任意自定义的转换(转换也就是对消息进行业务操作)。

这个 sink主题并不是指具体的一个叫sink的主题,只是类似于 源和目标 中的目标一样。
我把某个主题的方法导流到另一个主题上面去而已。这个sink主题也可以是a主题,也可以是b主题。

在这里插入图片描述



流API的核心API:


流API 的核心API包括如下几个:

StreamsBuilder: 从名称就知道,它的作用是创建Stream。但它不是直接创建KafkaStream,而是创建KStream。

KStream: KStream 代表key-value数据流,它的主要功能就是定义流的拓扑(Topology)结构。通俗来说,就是设置source主题,设置sink主题等。

Topology: 代表流的拓扑(Topology)结构,它也提供了大量重载的 addSource()、addSink()方法来添加 source主题 和 sink主题。

KafkaStreams: 代表程序要用到的数据流,调用它的 start()方法开始导流,调用它的 close()方法可关闭导流。



使用流API编程的大致步骤如下:

1、使用StreamsBuilder创建KStream,创建KStream时已经指定了source主题。

2、通过KStream设置sink主题、要流所做到转换处理。

KStream提供了大量重载的flatMap()、map()、filter()……等方法对流进行转换, 调用这些处理方法时,通常都需要传入自定义的处理器,常使用Lambda表达式来定义这些处理器。

3、调用StreamsBuilder的build()方法创建代表流关系的Topology对,该对象已经封装了通过KSteam所设置的source主题、sink主题等信息。

如果还需要对流关系进行修改,也可调用Topology对象的addSource()、addSink()方法来添加source主题和sink主题。

4、以Topology为参数,创建KafkaStreams对象,创建该对象时,还需要传入一个Properties对象对该流进行配置。

5、调用KafkaStreams对象的start()方法开始导流;导流结束后调用 close()方式关闭流。

流API要使用自己的依赖库:

	<!-- 导入Kafka流API的JAR包 -->
	<dependency>
		<groupId>org.apache.kafka</groupId>
		<artifactId>kafka-streams</artifactId>
		<version>3.6.1</version>
	</dependency>

依赖
在这里插入图片描述



代码演示 流API 用法


KafkaStreams 官方API 示例

在这里插入图片描述



MessageStream 流API 代码


这个导流的类,功能就是把test1主题的消息自动导流到test2主题里面,导流的时候还对消息做了业务处理,就是在消息前面加上 "【 ljh: " 这个字符串操作

在这里插入图片描述
在这里插入图片描述

启动 流API 这个类,开始导流

在这里插入图片描述



演示消息从 test1主题 导流到 test2主题


前景提要,消费者01和消费者02都是在监听test2这个主题的消息的。

在这里插入图片描述

两个消费者在不同的消费者组,所以都可以监听到test2主题的所有消息。类似发布/订阅模式。

在这里插入图片描述

打开一个小黑窗,往test1主题发送消息

C:\Users\JH> kafka-console-producer --bootstrap-server localhost:9092 ^
More? --topic test1

在这里插入图片描述

导流成功:

如图:我往 test1主题 发送的消息,因为成功导流到 test2 主题,所以也被消费者01 和 消费者02 监听到了。
而且消息也做了处理,在消息前面加了–> 【 ljh:

在这里插入图片描述

5分钟后,导流结束,关闭这个导流功能的线程。

在这里插入图片描述



演示使用匿名内部类对消息进行处理


通过代码处理,以空格为分割点,将带有空格的消息分割成多个消息
此处是一条消息,转换后变成多条消息

在这里插入图片描述


如图:发送的这一条消息,带有多个空格

在这里插入图片描述

通过业务处理后,一条消息通过空格,分割成6条消息

在这里插入图片描述



Topology 拓扑结构 讲解

调用StreamsBuilder的build()方法创建代表流关系的Topology对像,该对象已经封装了通过KSteam所设置的 source主题、sink主题等信息。如果还需要对流关系进行修改,也可调用Topology对象的addSource()、addSink()方法来添加source主题和sink主题。

通过打印这个拓扑结构,看下我们设置的 source主题、sink主题等信息。

如图:我们设置的 source主题 就是 test1 主题,设置的 sink主题 就是test2 主题

在这里插入图片描述

代码:

MessageProducer 消息生产者

这个在演示中用不到,不过为了方便后期研究,也贴上来

package cn.ljh;

import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.Producer;
import org.apache.kafka.clients.producer.ProducerRecord;

//生产者
import java.util.Properties;

/**
 * Properties: Kafka 设计了 Properties 来封装所有的配置属性
 * <p>
 * KafkaProducer:用来创建消息生产者,是 生产者API 的核心类,
 * 它提供了一个 send()方法 来发送消息,该方法需要传入一个 ProducerRecord<K,V>对象
 * <p>
 * ProducerRecord:代表了一条消息,Kafka 的消息是包含了key、value、timestamp
 */
public class MessageProducer
{
    //主题常量
    public static final String TEST_TOPIC = "test2";

    public static void main(String[] args)
    {

        //Properties 中所设置的key,有效的value,可以通过Kafka官方文档来查询生产者API支持哪些配置属性
        Properties props = new Properties();
        //指定连接Kafka的地址,多个地址之间用逗号隔开
        props.put("bootstrap.servers", "localhost:9092,localhost:9093,localhost:9094");
        //指定Kafka的消息确认机制
        //0:不等待消息确认;1:只等待领导者分区的消息写入之后确认;all:等待所有分区的消息都写入之后才确认
        props.put("acks", "all");
        //指定消息发送失败的重试多少次
        props.put("retries", 0);
        //控制生产者在发送消息之前等待的时间
        //props.put("linger.ms", 3);
        //设置序列化器
        props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");

        //1、创建 KafkaProducer 时,需要传入 Properties 对象来配置消息生产者
        Producer<String, String> producer = new KafkaProducer<>(props);

        //2、发送消息
        for (int i = 0; i < 20; i++)
        {
            var msg = "这是第【 " + (i + 1) + " 】条消息!";
            if (i < 10)
            {
                //发送带 key 的消息
                producer.send(new ProducerRecord<String, String>(TEST_TOPIC, "ljh", msg));

            } else
            {
                //发送不带 key 的消息
                producer.send(new ProducerRecord<String, String>(TEST_TOPIC, msg));
            }
        }
        System.out.println("消息发送成功!");
        //3、关闭资源
        producer.close();
    }
}

Consumer01 消费者01

package cn.ljh;

import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;

import java.time.Duration;
import java.util.Arrays;
import java.util.Properties;
import java.util.Scanner;
//消费者01
public class Consumer01
{
    //组id:设置这个消费者实例是属于 ConsumerGroupTest_01 这个消费者组的
    public static final String GROUP_ID = "ConsumerGroupTest_01";

    //1、创建 KafkaConsumer 消费者对象 ,把这个消费者定义成成员变量
    public static KafkaConsumer<String, String> consumer = null;

    public static void main(String[] args)
    {
        //Properties 中所设置的key,有效的value,可以通过Kafka官方文档来查询生产者API支持哪些配置属性
        Properties props = new Properties();

        //指定连接Kafka的地址,多个地址之间用逗号隔开
        props.put("bootstrap.servers", "localhost:9092,localhost:9093,localhost:9094");

        //设置这个消费者实例属于哪个消费者组
        props.setProperty("group.id", GROUP_ID);

        //自动提交offset,就是类似之前的自动消息确认
        props.setProperty("enable.auto.commit", "true");

        //多个消息之间,自动提交消息的时间间隔
        props.setProperty("auto.commit.interval.ms", "1000");

        //设置session的超时时长,默认是10秒,这里设置15秒
        props.setProperty("session.timeout.ms", "15000");

        //设置每次都从最新的消息开始读取
        props.setProperty("auto.offset.reset","latest");

        //设置序列化器
        props.setProperty("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        props.setProperty("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");

        //1、创建 KafkaConsumer 消费者对象
        consumer = new KafkaConsumer<>(props);

        //2、订阅主题,订阅kafka集群中的test2主题
        consumer.subscribe(Arrays.asList(MessageProducer.TEST_TOPIC));

        //因为获取消息的循环是一个死循环,没法退出,所以我在这里再加一个线程来关闭这个消费者
        //启动一个线程来关闭这个 KafkaConsumer
        new Thread(() ->
        {
            //创建一个Scanner 类来读取控制台数据
            Scanner sc = new Scanner(System.in);
            //如果有下一行,就读取下一行
            while (sc.hasNextLine())
            {
                //获取控制台下一行的内容
                var str = sc.nextLine();
                //就是这个线程一直监听控制台,如果我们在控制台输出” :exit “,则关闭这个这个 KafkaConsumer
                if (str.equals(":exit"))
                {
                    //取消订阅
                    consumer.unsubscribe();
                    //关闭消费者对象
                    consumer.close();
                }
            }

        }).start();

        //这是一个死循环,一直在获取主题中的消息
        while (true)
        {
            ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(100));
            for (ConsumerRecord<String, String> record : records)
                System.out.printf("收到消息: offset = %d, key = %s, value = %s%n",
                        record.offset(), record.key(), record.value());
        }

    }
}

Consumer02 消费者02

package cn.ljh;

import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;

import java.time.Duration;
import java.util.Arrays;
import java.util.Properties;
import java.util.Scanner;
//消费者02
public class Consumer02
{
    //组id:设置这个消费者实例是属于 ConsumerGroupTest_02 这个消费者组的
    public static final String GROUP_ID = "ConsumerGroupTest_02";

    //1、创建 KafkaConsumer 消费者对象 ,把这个消费者定义成成员变量
    public static KafkaConsumer<String, String> consumer = null;

    public static void main(String[] args)
    {

        //Properties 中所设置的key,有效的value,可以通过Kafka官方文档来查询生产者API支持哪些配置属性
        Properties props = new Properties();
        //指定连接Kafka的地址,多个地址之间用逗号隔开
        props.put("bootstrap.servers", "localhost:9092,localhost:9093,localhost:9094");
        //设置这个消费者实例属于哪个消费者组
        props.setProperty("group.id", GROUP_ID);
        //自动提交offset,就是类似之前的自动消息确认
        props.setProperty("enable.auto.commit", "true");
        //多个消息之间,自动提交消息的时间间隔
        props.setProperty("auto.commit.interval.ms", "1000");
        //设置session的超时时长,默认是10秒,这里设置15秒
        props.setProperty("session.timeout.ms", "15000");

        //设置每次都从最新的消息开始读取
        props.setProperty("auto.offset.reset","latest");

        //设置序列化器
        props.setProperty("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        props.setProperty("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");

        //1、创建 KafkaConsumer 消费者对象
        consumer = new KafkaConsumer<>(props);

        //2、订阅主题,订阅kafka集群中的test2主题
        consumer.subscribe(Arrays.asList(MessageProducer.TEST_TOPIC));

        //因为获取消息的循环是一个死循环,没法退出,所以我在这里再加一个线程来关闭这个消费者
        //启动一个线程来关闭这个 KafkaConsumer
        new Thread(() ->
        {
            //创建一个Scanner 类来读取控制台数据
            Scanner sc = new Scanner(System.in);
            //如果有下一行,就读取下一行
            while (sc.hasNextLine())
            {
                //获取控制台下一行的内容
                var str = sc.nextLine();
                //就是这个线程一直监听控制台,如果我们在控制台输出” :exit “,则关闭这个这个 KafkaConsumer
                if (str.equals(":exit"))
                {
                    //取消订阅
                    consumer.unsubscribe();
                    //关闭消费者对象
                    consumer.close();
                }
            }

        }).start();


        //这是一个死循环,一直在获取主题中的消息
        while (true)
        {
            ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(100));
            for (ConsumerRecord<String, String> record : records)
                System.out.printf("收到消息: offset = %d, key = %s, value = %s%n",
                        record.offset(), record.key(), record.value());
        }


    }
}

MessageStream 流API 功能演示类

package cn.ljh;

import org.apache.kafka.common.serialization.Serdes;
import org.apache.kafka.streams.KafkaStreams;
import org.apache.kafka.streams.StreamsBuilder;
import org.apache.kafka.streams.StreamsConfig;
import org.apache.kafka.streams.Topology;
import org.apache.kafka.streams.kstream.ValueMapper;

import java.util.Arrays;
import java.util.Properties;

//流API
public class MessageStream
{
    //定义常量,这个是主题的常量
    public static final String SOURCE_TOPIC = "test1";
    public static final String TO_TOPIC = "test2";

    public static void main(String[] args) throws InterruptedException
    {

        //1、使用StreamsBuilder创建KStream
        StreamsBuilder builder = new StreamsBuilder();

        //2、通过KStream设置sink主题、要流所做到转换处理。
        // KStream提供了大量重载的flatMap()、map()、filter()……等方法对流进行转换,
        // 调用这些处理方法时,通常都需要传入自定义的处理器,常使用Lambda表达式来定义这些处理器。

        builder
                //设置 source 主题,类似的源的主题
                .<String, String>stream(SOURCE_TOPIC)

                //这里的 mapValues 就是对消息(数据项、记录)进行转换处理(也可以理解为业务处理),这里我在消息前面加上 "【 ljh:  " 这个字符串操作
                //使用lambda表达式来构建转换器
                //此处是一条消息,转换后也还是一条消息,只是在消息内容的前后添加特定的字符串
                //.mapValues(value -> "【 ljh:  " + value + "  】")

                //此处使用匿名内部类构建转换器
                .flatMapValues(new ValueMapper<String, Iterable<String>>()
                {
                    @Override
                    //该方法的参数就代表传入的一个数据项(消息)
                    public Iterable<String> apply(String value)
                    {
                        //Arrays.asList : 把一个数组转换成list
                        //value.split("\\w+") :( 一条带有空格的消息)通过空格将消息分解成多个消息
                        //此处是一条消息,转换后变成多条消息
                        return Arrays.asList(value.split("\\W+"));
                    }
                })

                //设置sink主题:就是把test01主题的消息导流到这个test02主题
                .to(TO_TOPIC);


        //Properties: Kafka 设计了 Properties 来封装所有的配置属性
        Properties props = new Properties();

        props.put(StreamsConfig.APPLICATION_ID_CONFIG, "my-stream-processing-application");

        //指定连接Kafka的地址,多个地址之间用逗号隔开
        props.put(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092,localhost:9093,localhost:9094");

        //设置 key 的序列化器
        props.put(StreamsConfig.DEFAULT_KEY_SERDE_CLASS_CONFIG, Serdes.String().getClass());

        //设置 value 的序列化器
        props.put(StreamsConfig.DEFAULT_VALUE_SERDE_CLASS_CONFIG, Serdes.String().getClass());

        //3、调用StreamsBuilder的build()方法创建代表流关系的Topology对像,该对象已经封装了通过KSteam所设置的source主题、sink主题等信息。
        //如果还需要对流关系进行修改,也可调用Topology对象的addSource()、addSink()方法来添加source主题和sink主题。

        Topology topology = builder.build();
        System.err.println(topology.describe());

        //4、以Topology为参数,创建KafkaStreams对象,创建该对象时,还需要传入一个Properties对象对该流进行配置。
        KafkaStreams streams = new KafkaStreams(builder.build(), props);

        //5、调用KafkaStreams对象的start()方法开始导流;导流结束后调用 close()方式关闭流。

        //调用 KafkaStreams 对象的 start() 方法开始导流
        streams.start();

        System.err.println("---------开始导流----------");

        //程序暂停300秒后停止导流
        Thread.sleep(300 * 1000);
        streams.close();

        System.err.println("---------导流结束----------");

    }
}

pom 依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>cn.ljh</groupId>
    <artifactId>kafkaproducertest</artifactId>
    <version>1.0.0</version>
    <!-- 项目名,和 artifactId 保持一致 -->
    <name>kafkaproducertest</name>


    <properties>
        <!-- 在这里指定编译器的版本 -->
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <java.version>11</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <!-- 导入 Kafka 客户端API的JAR包 -->
        <dependency>
            <groupId>org.apache.kafka</groupId>
            <artifactId>kafka-clients</artifactId>
            <version>3.6.1</version>
        </dependency>

        <!-- 导入Kafka 流API 的JAR包 -->
        <dependency>
            <groupId>org.apache.kafka</groupId>
            <artifactId>kafka-streams</artifactId>
            <version>3.6.1</version>
        </dependency>

    </dependencies>

</project>

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

程序员该懂的一些测试(二)单元测试与集成测试

集成测试才是目的 单元测试只是对每个小模块进行的测试&#xff0c;可以理解成每次提交的一个小功能。 最终系统的良好运行依赖于这些小模块之间良好协作。所以需要有集成测试 集成测试回滚数据&#xff0c;保证测试的可重复性 我们可以把 ApplicationContext 理解成 DI 容器…

Transformer and Pretrain Language Models3-6

Pretrain Language Models预训练语言模型 content&#xff1a; language modeling&#xff08;语言模型知识&#xff09; pre-trained langue models(PLMs&#xff09;&#xff08;预训练的模型整体的一个分类&#xff09; fine-tuning approaches GPT and BERT&#xff08;…

【探索科技 感知未来】文心一言大模型

【探索科技 感知未来】文心大模型 &#x1f6a9;本文介绍 文心一言大模型是由中国科技巨头百度公司研发的一款大规模语言模型&#xff0c;其基于先进的深度学习技术和海量数据训练而成。这款大模型具备强大的自然语言处理能力&#xff0c;可以理解并生成自然语言&#xff0c;为…

JVM-字节码应用

一、字节码的应用远超你的想象 二、ASM介绍与读取字节码实战 用CoreAPI解析和TreeAPI都能做字节码解析&#xff0c;区别&#xff0c;TreeAPI必须读取完整字节码信息&#xff0c;才能做解析。 下面代码&#xff0c;使用CoreAPI做解析&#xff1a; package asm;public class MyM…

leetcode.2846. 边权重均等查询【lca+树形dp】

原题链接&#xff1a;2846. 边权重均等查询 题目描述&#xff1a; 现有一棵由 n 个节点组成的无向树&#xff0c;节点按从 0 到 n - 1 编号。给你一个整数 n 和一个长度为 n - 1 的二维整数数组 edges &#xff0c;其中 edges[i] [ui, vi, wi] 表示树中存在一条位于节点 ui …

微服务-微服务Alibaba-Nacos注册中心实现

1. 系统架构的演变 俗话说&#xff0c; 没有最好的架构&#xff0c;只有最合适的架构。 微服务架构也是随着信息产业的发展而出现的最有普 遍适用性的一套架构模式。通常来说&#xff0c;我们认为架构发展历史经历了这样一个过程&#xff1a;单体架构——> 垂直架构 ——&g…

leetcode 42.接雨水

问题1&#xff1a;怎么算接水量 总的接水量第一列接水量第二列接水量第三列接水量…最后一列接水量 问题2&#xff1a;当前列的接水量怎么计算 当前的接水量min(当前列左边最高的墙x1&#xff0c;当前列右边最高的墙x3&#xff09;- 当前列x2的高度 问题2图解&#xff1a; …

蓝桥杯-sort排序(上)

sort排序 &#x1f388;1.算法说明&#x1f388;2.例题&#x1f52d;2.1例题一&#x1f52d;2.2例题二&#x1f52d;2.3例题三&#x1f52d;2.4例题四&#x1f52d;2.5例题五&#x1f52d;2.6例题六 &#x1f388;1.算法说明 &#x1f50e;对于一个数组&#xff0c;通过对数组中…

新版UI界面影视小程序亲测无问题带详细搭建教程

新版UI界面影视小程序亲测无问题带详细搭建教程 环境php7.0 — fileinfo–redis–sg11 mysql5.5 apache2.4 添加站点php7.0—-创建ftp—-上传后端文件《后端文件修改&#xff0c;/maccms/wxapi/config/dbs.php–修改当前数据库》—-设置ssl—-打开数据库安装cms 安装好后管…

如何写出有效的单元测试?

什么是单元测试 《单元测试的艺术》中对单元测试的定义&#xff1a; 一个单元测试是一段自动化的代码&#xff0c;这段代码调用被测试的工作单元&#xff0c;之后对这个单元的单个最终结果的某些假设进行校验。 单元测试几乎都是用单元测试框架编写的&#xff1b;只要产品代码…

免费数据恢复软件,帮你轻松恢复丢失数据!

“由于我经常会丢失各种文件&#xff0c;因此非常需要一款实用又有效的数据恢复软件&#xff0c;大家有什么推荐的吗&#xff1f;希望能给我出出主意&#xff01;” 随着数字技术的不断发展&#xff0c;数据恢复软件在我们的生活中扮演着越来越重要的角色。当我们的硬盘或其他存…

Bluetooth Device Address(BD_ADDR) - 2

蓝牙核心规范&#xff1a;Core v5.3中关于蓝牙地址的其他说明 Vol 3: Host, Part C: Generic Access Profile 3 User interface aspects 3.2 Representation of Bluetooth parameters 3.2.1 Bluetooth Device Address (BD_ADDR) BD_ADDR 是蓝牙设备使用的地址。在设备发现过…

nav02 学习03 机器人传感器

机器人传感器 移动机器人配备了大量传感器&#xff0c;使它们能够看到和感知周围的环境。这些传感器获取的信息可用于构建和维护环境地图、在地图上定位机器人以及查看环境中的障碍物。这些任务对于能够安全有效地在动态环境中导航机器人至关重要。 机器人的传感器类似人的感官…

单片机学习笔记---独立按键控制LED状态

上一节学习的是独立按键控制LED亮灭 这一节我们先来讲一下按键的抖动&#xff1a; 对于机械开关&#xff0c;当机械触点断开、闭合时&#xff0c;由于机械触点的弹性作用&#xff0c;一个开关在闭合时不会马上稳定地接通&#xff0c;在断开时也不会一下子断开&#xff0c;所以…

Leetcode刷题笔记题解(C++):1971. 寻找图中是否存在路径

思路&#xff1a; 1.建立图集&#xff0c;二维数组&#xff0c;path[0]里面存放的就是与0相连的节点集合 2.用布尔数组来记录当前节点是否被访问过&#xff0c;深度优先会使用到 3.遍历从起点开始能直接到达的点&#xff08;即与起点相邻的点&#xff09;&#xff0c;判断那…

判断给定的字符串s是否为Python的保留关键字keyword.iskeyword(s)

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 判断给定的字符串s 是否为Python的保留关键字 keyword.iskeyword(s) [太阳]选择题 请问以下代码输出的结果是&#xff1f; import keyword print("【执行】keyword.iskeyword(for)"…

【蓝桥杯冲冲冲】[NOIP2000 提高组] 方格取数

蓝桥杯备赛 | 洛谷做题打卡day19 文章目录 蓝桥杯备赛 | 洛谷做题打卡day19[NOIP2000 提高组] 方格取数题目背景题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 提示题解代码我的一些话 [NOIP2000 提高组] 方格取数 题目背景 NOIP 2000 提高组 T4 题目描述 设有 N N…

PBM模型学习(五)UDF生长模型

DEFINE_PB_GROWTH_RATE(name, cell, thread, d_i) 该UDF在每个时间步开始时执行,只有在时间步开始时,颗粒粒径才会更新,同时才会UDF才会向文件写入数据GR单位是m/sC_PHASE DIAMETER(c,ts):返回颗粒粒径???,ts为颗粒相的线程C_VOF(cell,thread):颗粒相总体积C_PB DISCI(c…

Kotlin快速入门系列2

Kotlin的基本数据类型 Kotlin 的基本数值类型包括 Byte、Short、Int、Long、Float、Double 等。不同于 Java 的是&#xff0c;字符不属于数值类型&#xff0c;是一个独立的数据类型。 Java和kotlin数据类型对照如下&#xff1a; Java基本数据类型 Kotlin对象数据类型 数据类…

vue3+naiveUI二次封装的v-model 联动输入框

根据官网说明使用 源码 <template><div class"clw-input pt-3"><n-inputref"input":value"modelValue":type"type":title"title"clearable:disabled"disabled":size"size"placeholder&…