Windows安装和使用kafka

一、安装kafka

由于kafka依赖jdk和zookeeper,安装kafka之前需要先安装jdk和zookeeper,也可以使用kafka自带的zookeeper。安装jdk可以参考:Windows和Linux安装jdk,此处使用kafka自带的zookeeper,不单独安装。

下面在Windows系统中安装kafka时使用的ip地址是192.168.10.188,这是我自己电脑的ip。

1、下载kafka

2、修改配置文件

修改zk和kafka的配置文件。

修改zk的配置文件:

配置上面创建的mydata目录,用于保存zookeeper的数据。

修改kafka的配置文件:

在kafka的配置文件中主要是创建或修改port、host.name、listeners、log.dirs和zookeeper.connect这五个参数。其中port就是kafka的端口号,默认是9092。host.name是当前计算机的ip地址。log.dirs就是上面创建的mylog目录,用于保存kafka的数据。zookeeper.connect参数的作用是kafka连接zookeeper,在下面创建topic时也需要用到此处配置的ip:port,默认配置是zookeeper.connect=localhost:2181。

3、启动zk和kafka

启动zk

进入到kafka的安装目录kafka_2.11-1.0.0下,同时按住shift和鼠标右键,选择“打开命令窗口”选项,或者win+R输入cmd,打开命令行窗口。

输入启动zk的命令:

bin\windows\zookeeper-server-start.bat config\zookeeper.properties

这个dos窗口不要关闭,再次进入到kafka的安装目录kafka_2.11-1.0.0下,同时按住shift和鼠标右键,选择“打开命令窗口”选项,又打开一个命令行窗口,输入启动kafka的命令。

启动kafka

bin\windows\kafka-server-start.bat config\server.properties

4、创建topic

重新打开一个dos窗口,创建topic。

bin\windows\kafka-topics.bat --zookeeper 192.168.10.188:2181 --create --replication-factor 1 --partitions 1 --topic kjTest

如果在kafka的配置文件中没有配置zookeeper.connect,或者配置的是zookeeper.connect=localhost:2181,创建topic时--zookeeper参数就要使用localhost:2181,2181是zookeeper的默认端口号。

查看创建的topic列表:

bin\windows\kafka-topics.bat --zookeeper 192.168.10.188:2181 --list

__consumer_offsets这个topickafka自动创建的,当consumer消费数据之后,consumer就会把offset提交到__consumer_offsets中。

删除topic

bin\windows\kafka-topics.bat --zookeeper 192.168.10.188:2181 --delete --topic kjTest

5、启动producer和consumer

在介绍启动producer和consumer的命令之前,先简单了解一下broker-list、bootstrap-servers和zookeeper。

1.broker:kafka服务端,可以是一个服务器也可以是一个集群。producer和consumer都相当于这个服务端的客户端。

2.broker-list:指定kafka集群中的一个或多个服务器,一般在使用kafka-console-producer.sh的时候,这个参数是必备参数,另外一个必备的参数是topic。

3.bootstrap-servers指的是kafka目标集群的服务器地址,这和broker-list功能一样,不过在启动producer时要求用broker-list,在启动consumer时用bootstrap-servers。

4. zookeeper指的是zk服务器或zk集群的地址。旧版本(0.9以前)的kafka,消费的进度(offset)是写在zk中的,所以启动consumer需要知道zk的地址。后来的版本都统一由broker管理,所以在启动consumer时就用bootstrap-server。

重新打开两个dos窗口,分别启动producer和consumer。

启动producer并输入内容:

bin\windows\kafka-console-producer.bat --broker-list 192.168.10.188:9092 --topic kjTest

启动consumer查看消息:

bin\windows\kafka-console-consumer.bat --zookeeper 192.168.10.188:2181 --topic kjTest --from-beginning

上面是旧版本的写法,下面是新版本的写法。

bin\windows\kafka-console-consumer.bat --bootstrap-server 192.168.10.188:9092 --topic kjTest --from-beginning

参数--zookeeper 192.168.10.188:2181中的ip和port是zookeeper节点的ip和zookeeper的port,参数--bootstrap-server 192.168.10.188:9092中的ip和port是kafka节点的ip和kafka的port。

6、查看消费者组以及消息是否积压

查看消费者组的命令:

bin\windows\kafka-consumer-groups.bat --bootstrap-server localhost:9092 --list

查看消息是否有积压的命令:

bin\windows\kafka-consumer-groups.bat --bootstrap-server localhost:9092 --describe --group consumer-group-01

上图中GROUP表示消费者组,TOPIC表示消息主题,PARTITION表示分区,CURRENT-OFFSET表示当前消费的消息条数,LOG-END-OFFSET表示kafka中生产的消息条数,LAG表示kafka中有多少条消息还未消费,也就是有多少条积压的消息。

在kafka中,消费者是按批次拉取数据的,每一批次拉取的数据条数是0-n条,每个消费者可以拉取多个分区的数据,但是一个分区的数据只能被同一个消费者组中的一个消费者拉取。如果一个消费者拉取多个分区的数据,那么拉取的这一批次的数据就包含多个分区的数据。消费者处理完这批数据之后,会将offset提交到__consumer_offsets这个topic中,__consumer_offsets(是一个topic)就是用于维护消费者消费到哪条数据offset的,是按照分区粒度维护的,各个分区的offset是互不影响的。例如一个consumer拉取两个分区(p0、p1)的数据,如果p0分区的数据处理完并将offset提交到__consumer_offsets中,而p1分区的数据还未处理完,p1分区的offset还未提交到__consumer_offsets中,此时consumer异常重启,consumer不会再拉取p0分区上次已消费的数据,但是会重新拉取p1分区上次消费但未提交的数据。

7、异常

启动consumer时可能会报下面的异常:

kafka的consumer:java.nio.channels.ClosedChannelException

解决方法:

出现以上异常是由于服务器没有做kafka的主机名与ip的映射,

linux的目录是/etc/hosts

windows的目录是C:\Windows\System32\drivers\etc\hosts

二、创建生产者和消费者

上面在Windows中安装好kafka之后,就可以在idea中操作kafka了。

项目结构:

pom.xml文件

<?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>org.example</groupId><artifactId>kafka-study</artifactId><version>1.0-SNAPSHOT</version><dependencies><dependency><groupId>org.apache.kafka</groupId><artifactId>kafka_2.12</artifactId><version>2.7.0</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.2</version></dependency></dependencies></project>

1、配置kafka相关参数

package com.example.kafka.config;import org.apache.kafka.common.serialization.StringDeserializer;
import org.apache.kafka.common.serialization.StringSerializer;/*** 此处为了简化,直接将kafka配置信息写到代码中,* 实际项目中需要从application.yml配置文件中读取** @Author: 倚天照海*/
public class MyKafkaConfig {/*** kafka集群地址,多个地址用逗号分隔*/private String bootstrapServer = "localhost:9092";private String topic = "testKafka";/*** 消费者组*/private String consumerGroupId = "consumer-group-01";/*** kafka中保存的是将数据序列化后的字节数组,需要指定key和value的序列化方式*/private String keySerializerClass = StringSerializer.class.getName();private String valueSerializerClass = StringSerializer.class.getName();/*** kafka中key和value的反序列化方式*/private String keyDeserializerClass = StringDeserializer.class.getName();private String valueDeserializerClass = StringDeserializer.class.getName();public String getBootstrapServer() {return bootstrapServer;}public String getTopic() {return topic;}public String getConsumerGroupId() {return consumerGroupId;}public String getKeySerializerClass() {return keySerializerClass;}public String getValueSerializerClass() {return valueSerializerClass;}public String getKeyDeserializerClass() {return keyDeserializerClass;}public String getValueDeserializerClass() {return valueDeserializerClass;}
}

2、编写producer

根据公司业务逻辑编写producer,用于生产消息。

package com.example.kafka.producer;import com.example.kafka.config.MyKafkaConfig;
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.clients.producer.RecordMetadata;import java.util.Properties;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;/*** kafka生产者* 创建kafka生产者并生产消息的步骤:* 1.启动zookeeper和kafka* 2.创建topic* 3.启动producer** @Author: 倚天照海*/
public class MyProducer {/*** 1.创建topic:进入到kafka安装目录的bin目录下,执行kafka-topics.sh(Linux系统)或windows\kafka-topics.bat(windows系统)脚本* Linux系统: bin/kafka-topics.sh --zookeeper 192.168.10.188:2181/kafka --create --replication-factor 2 --partitions 2 --topic testKafka* windows系统: bin\windows\kafka-topics.bat --zookeeper 192.168.10.188:2181 --create --replication-factor 2 --partitions 2 --topic testKafka* 2.启动producer* Linux系统: bin/kafka-console-producer.sh --broker-list 192.168.10.188:9092 --topic testKafka* windows系统: bin\windows\kafka-console-producer.bat --broker-list 192.168.10.188:9092 --topic testKafka*/public void produce() throws ExecutionException, InterruptedException {MyKafkaConfig kafkaConfig = new MyKafkaConfig();Properties properties = new Properties();properties.setProperty(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, kafkaConfig.getBootstrapServer());properties.setProperty(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, kafkaConfig.getKeySerializerClass());properties.setProperty(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, kafkaConfig.getValueSerializerClass());String topic = kafkaConfig.getTopic();KafkaProducer<String, String> producer = new KafkaProducer<>(properties);doProduce(producer, topic);}private void doProduce(KafkaProducer<String, String> producer, String topic) throws ExecutionException, InterruptedException {while (true) {for (int i = 0; i < 3; i++) {for (int j = 0; j < 3; j++) {ProducerRecord<String, String> record = new ProducerRecord<>(topic, "item" + j, "price" + i);Future<RecordMetadata> future = producer.send(record);RecordMetadata recordMetadata = future.get();int partition = recordMetadata.partition();long offset = recordMetadata.offset();System.out.println("key=" + record.key() + ", value=" + record.value()+ ", partition=" + partition + ", offset=" + offset);}}}}
}

3、编写consumer

编写consumer,用于接受消息。

package com.example.kafka.consumer;import com.example.kafka.config.MyKafkaConfig;
import org.apache.kafka.clients.consumer.*;
import org.apache.kafka.common.TopicPartition;import java.time.Duration;
import java.util.*;/*** @Author: 倚天照海*/
public class MyConsumer {public void consume() {MyKafkaConfig kafkaConfig = new MyKafkaConfig();Properties properties = new Properties();properties.setProperty(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, kafkaConfig.getBootstrapServer());properties.setProperty(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, kafkaConfig.getKeyDeserializerClass());properties.setProperty(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, kafkaConfig.getValueDeserializerClass());properties.setProperty(ConsumerConfig.GROUP_ID_CONFIG, kafkaConfig.getConsumerGroupId());/*** ConsumerConfig.AUTO_OFFSET_RESET_CONFIG表示当kafka中未初始化offset或当前offset不存在时,消费者自动重置offset的方式,默认是latest。* What to do when there is no initial offset in Kafka* or if the current offset does not exist any more on the server (e.g. because that data has been deleted):* <ul>*     <li>earliest: automatically reset the offset to the earliest offset</li>*     <li>latest: automatically reset the offset to the latest offset</li>*     <li>none: throw exception to the consumer if no previous offset is found for the consumer's group</li>*     <li>anything else: throw exception to the consumer.</li>* </ul>*/properties.setProperty(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "latest");// 是否开启自动提交,默认开启。自动提交是异步提交,开启自动提交可能会造成数据丢失或重复消费数据// properties.setProperty(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, "true");// 自动提交的间隔时间(多长时间会触发自动提交),默认是5秒// properties.setProperty(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG, "10000");// kafka的消费者是按批次拉取数据,该参数是设置一批最多拉取多少条数据// properties.setProperty(ConsumerConfig.MAX_POLL_RECORDS_CONFIG, "1000");List<String> topics = Collections.singletonList(kafkaConfig.getTopic());KafkaConsumer<String, String> consumer = new KafkaConsumer<>(properties);doConsume(consumer, topics);}private void doConsume(KafkaConsumer<String, String> consumer, List<String> topics) {// 消费者订阅主题消息,多个consumer会动态负载均衡多个分区// 例如有两个分区,最开始只启动一个consumer,会给这个consumer分配两个分区,它会消费两个分区的数据。// 然后在同一个消费者组内又启动一个consumer,此时会把第一个consumer的两个分区都撤销,再随机给这两个consumer分别分配一个分区consumer.subscribe(topics, new ConsumerRebalanceListener() {@Overridepublic void onPartitionsRevoked(Collection<TopicPartition> partitions) {System.out.println("-----------------onPartitionsRevoked撤销的分区是:---------------");Iterator<TopicPartition> iterator = partitions.iterator();while (iterator.hasNext()) {TopicPartition next = iterator.next();System.out.println(next.partition());}}@Overridepublic void onPartitionsAssigned(Collection<TopicPartition> partitions) {System.out.println("-----------------onPartitionsAssigned分配的分区是:---------------");Iterator<TopicPartition> iterator = partitions.iterator();while (iterator.hasNext()) {TopicPartition next = iterator.next();System.out.println(next.partition());}}});while (true) {// 消费者拉取消息,设置等待时间,按批次拉取,一批拉取的数据是0-n条,每次poll是同时拉取多个分区的数据ConsumerRecords<String, String> consumerRecords = consumer.poll(Duration.ofMillis(0));while (!consumerRecords.isEmpty()) {// 每次拉取数据的条数System.out.println("----------------consumerRecords.count------------------" + consumerRecords.count());// 方式一:按分区分别处理每个分区的数据Set<TopicPartition> partitions = consumerRecords.partitions();// kafka中consumer是按照分区粒度提交维护offset的,将offset提交到__consumer_offsets中// 如果关闭自动提交,使用手动提交offset,则有三种粒度同步提交offset:// 1.按每条消息粒度同步提交offset// 2.按每个分区粒度同步提交offset// 3.按poll的一批数据粒度同步提交offset
//                for (TopicPartition topicPartition : partitions) {
//                    // 分别获取每个分区的数据记录,且分区内的数据是有序的,可以用多线程并行处理每个分区的数据
//                    List<ConsumerRecord<String, String>> partitionRecords = consumerRecords.records(topicPartition);
//                    for (ConsumerRecord<String, String> record : partitionRecords) {
//                        // 一个消费者可以消费多个分区,一个分区只能被同一个消费者组中的一个消费者消费
//                        int partition = record.partition();
//                        long offset = record.offset();
//                        // TODO 获取数据处理复杂的业务逻辑,最终将数据持久化到数据库中
//                        System.out.println("key=" + record.key() + ", value=" + record.value()
//                                + ", partition=" + partition + ", offset=" + offset);
//
//                        // 粒度1.按每条消息粒度同步提交offset
//                        /*OffsetAndMetadata offsetAndMetadata = new OffsetAndMetadata(offset);
//                        Map<TopicPartition, OffsetAndMetadata> map = new HashMap<>();
//                        map.putIfAbsent(topicPartition, offsetAndMetadata);
//                        consumer.commitSync(map);*/
//                    }
//                    // 粒度2.按每个分区粒度同步提交offset
//                    // 获取分区最后一条消息记录的offset,将offset提交到__consumer_offsets中
//                    long offset = partitionRecords.get(partitionRecords.size() - 1).offset();
//                    OffsetAndMetadata offsetAndMetadata = new OffsetAndMetadata(offset);
//                    Map<TopicPartition, OffsetAndMetadata> map = new HashMap<>();
//                    map.putIfAbsent(topicPartition, offsetAndMetadata);
//                    consumer.commitSync(map);
//                }// 粒度3.按poll的一批数据粒度同步提交offset// consumer.commitSync();// 方式二:不区分分区,将多个分区的数据放在一起逐条处理for (ConsumerRecord<String, String> record : consumerRecords) {// 一个消费者可以消费多个分区,一个分区只能被同一个消费者组中的一个消费者消费int partition = record.partition();long offset = record.offset();// TODO 获取数据处理复杂的业务逻辑,最终将数据持久化到数据库中System.out.println("key=" + record.key() + ", value=" + record.value()+ ", partition=" + partition + ", offset=" + offset);}consumer.commitSync();}}}
}

从kafka中消费数据,经过一系列逻辑处理之后将数据写入到数据库中,开启自动提交可能会造成数据丢失或重复消费数据。自动提交是异步提交,异步提交是指consumer提交offset与将数据持久化到数据库是异步的。
1.数据丢失:若开启自动提交,且自动提交的间隔时间(默认是5秒)到了,消费者会将拉取的这批数据的offset保存到_consumer_offsets中。但是5s内由于业务太过复杂,数据没有完全持久化,消费者就把offset提交了,若此时消费端consumer挂了,等消费端重启之后,会根据自身维护的offset拉取新的数据,不会重新拉取之前已消费的数据,因为这些数据的offset已经被提交了。
2.重复消费:若开启自动提交,且自动提交的间隔时间(默认是5秒)还未到,经过业务逻辑处理后将数据写入到了数据库中,此时消费者还未将拉取的这批数据的offset保存到_consumer_offsets中,若此时消费端consumer挂了,等消费端重启之后,会根据自身维护的offset拉取新的数据,会重新拉取之前已消费的数据,因为这些数据的offset还未被提交。

4、编写测试类

package com.example.kafka;import com.example.kafka.consumer.MyConsumer;
import com.example.kafka.producer.MyProducer;
import org.junit.Test;import java.util.concurrent.ExecutionException;/*** @Author: 倚天照海*/
public class Main {MyProducer myProducer = new MyProducer();MyConsumer myConsumer = new MyConsumer();@Testpublic void produceTest() {produceData();}@Testpublic void consumeTest() {consumeData();}private void produceData() {
//        MyProducer myProducer = new MyProducer();try {myProducer.produce();} catch (ExecutionException | InterruptedException e) {e.printStackTrace();}}private void consumeData() {
//        MyConsumer myConsumer = new MyConsumer();myConsumer.consume();}
}

测试结果:

生产者:

消费者:

Kafka中消息积压情况:

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

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

相关文章

VUE2/3:element ui table表格的显隐列(若依框架)

若依框架自带一个组件&#xff0c;封装了关于表格&#xff0c;展示和隐藏表格列的功能&#xff1b; 使用效果就是这样的&#xff0c;在表格上面&#xff0c;三个框&#xff0c;从左到右分别是隐藏上面搜索&#xff0c;刷新列表&#xff0c;和显隐列的功能&#xff1b; 一、下面…

每日一题 82. 删除排序链表中的重复元素 II(中等,链表)

和昨天差不多&#xff0c;今天的是把所有重复数字的节点都删除&#xff08;昨天留了一个&#xff09; 显然当我们发现重复数字时&#xff0c;需要重复的第一个数字的前一个节点才能把重复数字删完&#xff0c;所有在while循环中我们每次判断 t.next 和 t.next.next 的值是否重复…

互联网今年都崩盘了gis开发还有前途嘛?

互联网和GIS其实分不开的&#xff0c;尤其是在新兴技术领域。 互联网行业都已经在进军测绘、GIS以及智慧城市、无人驾驶等行业&#xff0c;随着高新技术的发展&#xff0c;互联网和GIS其实结合会越来越紧密。 传统互联网行业已经不能满足大众需求&#xff0c;近十年&#xff…

如何应对Android面试官->我用RecyclerView实现了吸顶效果

前言 RecyclerView 计划用两个章节来讲解&#xff0c;今天主要是以 itemDecoration 和 实现吸顶效果为主&#xff1b; ItemDecoration ItemDecoration 允许应用给具体的 View 添加具体的图画或者 Layout 的偏移&#xff0c;对于绘制 View 之间的分割线&#xff0c;视觉分组边…

用bat脚本执行py文件以及批量执行py文件(全网超详细)

1.前言 对于python代码&#xff0c;每次执行一个文件就要运行一个命令&#xff0c;太过麻烦 在Windows电脑上&#xff0c;想一次性执行多个python文件的代码&#xff0c;就需要用到bat脚本 2.python代码 先写几个python代码的文件 如下图 3.py文件为中文&#xff0c;用bat执…

如何使用CFImagehost结合内网穿透搭建私人图床并无公网ip远程访问

[TOC] 推荐一个人工智能学习网站点击跳转 1.前言 图片服务器也称作图床&#xff0c;可以说是互联网存储中最重要的应用之一&#xff0c;不仅网站需要图床提供的外链调取图片&#xff0c;个人或企业也用图床存储各种图片&#xff0c;方便随时访问查看。不过由于图床很不挣钱&a…

腾讯云价格计算器怎么用?太简单了一键报价

腾讯云服务器价格计算器可以一键计算出云服务器的精准报价&#xff0c;包括CVM实例规格价格、CPU内存费用、公网带宽收费、存储系统盘和数据盘详细费用&#xff0c;腾讯云百科txybk.com分享腾讯云价格计算器链接入口、使用方法说明&#xff1a; 腾讯云服务器价格计算器 打开腾…

❤ React报错问题分析

❤ React报错问题分析 ❤️ You passed a second argument to root.render(…) but it only accepts one argument. You passed a second argument to root.render(…) but it only accepts one argument. react-dom.development.js:86 Warning: You passed a second argumen…

css 居中方式

居中分为水平居中和垂直居中

C++ 数组分页,经常有用到分页,索性做一个简单封装 已解决

在项目设计中&#xff0c; 有鼠标滑动需求&#xff0c;但是只能说能力有限&#xff0c;索性使用 php版本的数组分页&#xff0c;解决问题。 经常有用到分页&#xff0c;索性做一个简单封装、 测试用例 QTime curtime QTime::currentTime();nHour curtime.hour();nMin curtim…

各种排序算法学习笔记

Docshttps://r0dhfl3ujy9.feishu.cn/docx/XFlEdnqv9oCEoVx7ok8cpc4knnf?fromfrom_copylink如果你认为有错误&#xff0c;欢迎指出&#xff01;

Three.js 镜面反射Reflector 为MeshStandardMaterial增加Reflector能力

效果效果官方案例 区别&#xff1a;官方的案例更像一个镜子 没有纹理等属性 也没有透明度修改 根据源码进行修改为 MeshStandardMaterial实现反射 使用案例 createReflector() {const plane this.helper.create.plane(2, 2);this.helper.add(plane.mesh);plane.mesh.rotat…

juniper EX系列交换机POE配置

PoE&#xff08;Power over Ethernet&#xff0c;以太网供电&#xff0c;又称远程供电&#xff09;是指设备通过以太网接口&#xff0c;利用双绞线对外接PD&#xff08;Powered Device&#xff0c;受电设备&#xff09;设备&#xff08;如IP 电话、无线AP、网络摄像头等&#x…

什么是视频短信,能用在什么地方?

视频短信是指通过106短信将带有视频的短信内容发送到对应的手机中&#xff0c;也称之为点对点的信息传递方式&#xff0c;视频短信可以支持2兆以内的多媒体信息发送&#xff0c;是直接、直观的宣传、沟通方式。 一、怎么就偏偏要找视频短信 根据目前的行情状况&#xff0c;尽管…

3d模型素材亮度和对比度如何调整呢?

1、修改材质参数&#xff1a;打开3ds Max后&#xff0c;选择要调整亮度和对比度的3D模型素材。然后&#xff0c;进入材质编辑器&#xff0c;选择相应的材质球。在材质编辑器中&#xff0c;你可以调整材质的漫反射、反射和高光等参数&#xff0c;这些参数将影响模型的亮度和对比…

C语言实现学生成绩管理系统(单链表)

本次我就用学到的相关链表知识总结回顾一下学生成绩管理系统的实现。 首先还是先创建一个项目&#xff0c;分别创建头文件和源文件&#xff0c;头文件用来声明函数&#xff0c;源文件用来定义函数以及实现学生成绩管理系统。 创建完成后如上图。 先创建一个结构体用来存放学生…

DaisyDisk for mac 中文激活版 可视化磁盘清理工具

DaisyDisk 是一款专为 Mac 设计的磁盘空间分析工具。它以直观、图形化的方式展示硬盘使用情况&#xff0c;帮助用户迅速找到占用空间大的文件和文件夹。通过扫描磁盘&#xff0c;DaisyDisk 生成彩色的扇形图表&#xff0c;每个扇区代表一个文件或文件夹&#xff0c;大小直观反映…

Java多线程并发篇----第十五篇

系列文章目录 文章目录 系列文章目录前言一、偏向锁二、分段锁三、锁优化四、线程基本方法前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给你的码吧。 一、偏向锁 Hotspot 的…

肯尼斯·里科《C和指针》第6章 指针(4)实例

肯尼斯里科《C和指针》第6章 指针&#xff08;1&#xff09;-CSDN博客 肯尼斯里科《C和指针》第6章 指针&#xff08;2&#xff09;-CSDN博客 肯尼斯里科《C和指针》第6章 指针&#xff08;3&#xff09;-CSDN博客 6.12 实例 /* ** 计算一个字符串的长度。 */ #include <…

leetcode 349 两个数组的集合

题目 给定两个数组 nums1 和 nums2 &#xff0c;返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。 示例 1&#xff1a; 输入&#xff1a;nums1 [1,2,2,1], nums2 [2,2] 输出&#xff1a;[2] 示例 2&#xff1a; 输入&#xff1a…