Go项目实战:02-微服务micro services

news2024/11/25 10:03:45

1、微服务(micro services)

请添加图片描述

单体式架构服务

过往大家熟悉的服务器。

特性:

  • 1、复杂性随着开发越来越高,遇到问题解决困难。
  • 2、技术债务逐渐上升。
  • 3、耦合度高,维护成本大。
    - 1、出现bug,不容易排查
    - 2、解决旧bug,会出新bug
  • 4、持续交付时间较长。
  • 5、技术选型成本高,风险大。
  • 6、扩展性较差
    - 1、垂直扩展:通过增加单个系统成员的负荷来实现扩展
    - 2、水平扩展:通过增加更多的系统成员来实现扩展

微服务架构

优点:

1、职责单一
2、轻量级通信 --可跨语言
3、独立性
4、迭代开发

缺点:

  • 1、运维成本高!
  • 2、分布式复杂度变高
  • 3、接口成本高
  • 4、重复性劳动
  • 5、业务分离困难–中台开发

单体式服务和微服务对比

请添加图片描述


2、RPC框架

2.1socket网络编程回顾

请添加图片描述

2.2RPC使用步骤

  • 服务端

1、注册rpc服务对象—要给对象绑定方法( 1、定义类,2、绑定类方法)

rpc.RegisterName("服务名", 回调对象)

2、创建监听器

listener, err := net.Listen()

3、建立连接

conn, err := listener.Accept()

4、将连接绑定rpc服务

rpc.ServeConn(conn)
  • 客户端

1、用rpc先去连接服务器 rpc.Dial()

conn, err := rpc.Dial()

2、调用远程函数

conn.Call("服务名.方法名", 传入参数, 传出参数)

2.3RPC相关函数

1、注册rpc服务

func (server *Server) RegisterName(name string, rcvr interface{}) error
参数1:服务名。字符串类型
参数2:对应的rpc对象。空接口类型。该对象绑定的方法要满足如下条件:
- 1、方法必须是导出的 -- 包外可见。 首字母大写。
- 2、方法必须有两个参数,并且都是导出类型(自定义的切片、map)、内建类型(int、double...)。
- 3、方法的第二个参数必须是**指针**(传出参数)
- 4、方法只有一个 **error** 接口类型的 **返回值**
- 举例:
type world struct {
} 
func (this * world ) Helloworld (name string, rest *string) error {
}
rpc.RegisterName("服务名", new(world))

2、绑定rpc服务

func (server *Server) ServeConn(conn io.ReadWriteCloser)

参数conn:成功建立好连接的socket–conn

3、调用远程函数

func (client *Client) Call(serviceMethod string, args interface{}, reply interface{}) error

参数1:“服务名.方法名”
参数2: 传入参数。方法所需要的数据。
参数3:传出参数。定义var变量,&变量名。完成传参


2.4编码实现

服务端
package main

import (
	"fmt"
	"net"
	"net/rpc"
)
//定义类对象
type  World struct{

}
//绑定类方法
func (this *World) HelloWrold (name string, resp * string) error {
	*resp = name + "你好!"
	return nil
}

func main() {
	//1、注册rpc服务,绑定对象方法
	err := rpc.RegisterName("hello", new(World))
	if err != nil {
		fmt.Println("注册rpc服务失败!", err)
		return
	}
	//2、设置监听
	listener, err := net.Listen("tcp", "127.0.0.1:8080")
	if err != nil {
		fmt.Println("net.Listen err: ", err)
		return
	}
	defer listener.Close()
	fmt.Println("开始监听...")
	//3、建立连接
	conn, err := listener.Accept()
	if err != nil {
		fmt.Println("listener.Accept(): ", err)
		return
	}
	defer conn.Close()
	fmt.Println("连接建立成功...")

	//4、绑定服务
	rpc.ServeConn(conn)



}
客户端
package main

import (
	"fmt"
	"net/rpc"
)

func main () {
	//1、 用rpc连接服务器--Dail()
	conn,err := rpc.Dial("tcp", "127.0.0.1:8080")
	if err != nil {
		fmt.Println("Dial err:", err)
		return
	}
	//2、调用远程函数
	var reply string //接收函数返回值--传出参数
	err = conn.Call("hello.HelloWrold", "李白", &reply)
	if err != nil {
		fmt.Println("Call err:", err)
		return
	}

	fmt.Println(reply)
}


2.5json 版rpc

  • 使用nc - 类127.0.0.1 8080 充当服务器
  • clinet.go 充当客户端,发起通信 —乱码
    - 因为:RPC使用了go语言特有的数据序列化gob。 其他编程语言不能解析。
  • 使用 通用的序列化和反序列化 ---- json、protobuf

修改客户端

conn,err := jsonrpc.Dial("tcp", "127.0.0.1:8080")

请添加图片描述

修改服务器端

jsonrpc.ServeConn(conn)
//终端1
go run server.go
//终端2
tianyi@SPACE-STATION src % echo -e '{"method":"hello.HelloWorld","params":["李白"],"id":0}' | nc 127.0.0.1 8080//使用nc - 类127.0.0.1 8080 充当服务器
//返回值
{"id":0,"result":"李白你好!","error":null}

如果,绑定方法返回值的error不为空?无论传出参数是否有值,服务端都不会返回数据

func (this *World) HelloWorld (name string, resp * string) error {
	*resp = name + "你好!"
	//return nil
	return errors.New("unknown error")//
}
tianyi@SPACE-STATION src % echo -e '{"method":"hello.HelloWorld","params":["李白"],"id":0}' | nc 127.0.0.1 8080  
{"id":0,"result":null,"error":"unknown error"}


2.6rpc封装

服务器端封装

1、

//定义接口
type xxx interface {
	方法名(传入参数, 传出参数) error 
}
//例: 
type MyIntercace Interface{
	HelloWorld(string, *string) error
}

2、

//封装注册服务方法
func RegisterService (I MyInterface) {
	rpc.RegisterName("hello", I)
}

客户端封装

1、

//定义类
type MyClient struct {
	c *rpc.Client	
}

2、

//绑定类方法
func (this *MyClient) HelloWorld (a string, b *string) error {
	return this.c.Call("hello.HelloWorld", a, b)	
}

3、

//初始化客户端
func Init (addr string) {
	conn,_ := jsonrpc.Dail("tcp", addr)	
}

3、protobuf 认识与使用

3.1 protobuf简介

Protobuf是Protocol Buffers的简称,它是Google公司开发的一种数据描述语言,是一种轻便高效的结构
化数据存储格式,可以用于结构化数据串行化,或者说序列化。它很适合做数据存储RPG数据交
换格式
。可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。目前 提供了C+、Java、Python三种语言的APl。

Protobuf刚开源时的定位类似于XML、JSON等数据描述语言,通过附带工具生成代码并实现将结构化数据序列化的功能。这里我们更关注的是Protobuf作为接口规范的描述语言,可以作为设计安全的跨语言
RPC接口的基础
工具。

需要了解两点
1。protobuf是类似与json一样的数据描述语言(数据格式)
2。protobuf非常适合于RPC数据交换格式

接着我们来看一下protobuf的优势和劣势:

优势:
1:序列化后体积相比json和XML很小,适合网络传输
2:支持跨平台多语言
3:消息格式升级和兼容性还不错
4:序列化反序列化速度很快,快于json的处理速度
劣势:
1:应用不够广(相比xml和json)
2:二进制格式导致可读性差
3:缺乏自描述

请添加图片描述

我们先安装一下protobuf,然后通过例子来看一下protobuf的具体作用。

3.2 protobuf的安装

1、下载protobuf

方法一: ===>git clone https://github.com/protocolbuffers/protobuf.git
方法二:=>或者将准备好的压缩包进行拖入
解压到$GOPATH/src/github.com/protocolbuffers/下面
Unzip protobuf.zip

2、安装(ubuntu)

(1)安装依赖工具(联网)
sudo apt-get install autoconf automake libtool curl make g++ unzip
libffi -dev -y
(2)进入protobuf文件
cd protobuf/
(3)进行安装检测 并生成自动安装脚本
/autogen.sh
./configure
(4)进行编译c代码
make
(5)进行安装
sudo make install
(6)刷新linux共享库关系
sudo ldconfig

3、测试protobuf工具

protoc -h
如果正常输出 相关指令 没有报任何error, 为安装成功

4、安装protobuf的go语言插件

由于protobuf并没有支持go语言需要我们手动安装相关插件
(1)下载
方法一:===>go get -v -u github.com/golang/protobuf/proto
方法二:=>或者将github.com-golang-protobuf.zip拖入 进行解压到
$GOPATH/src/github.com/golang
(2)进入到文件夹内进行编译
cd $GOPATH/src/github.com/golang/protobuf/protoc-gen-go
go build
(3)将生成的protoc-gen-go可执行文件,放在/bin目录下
sudo cp protoc-gen-go /bin/
(4)尝试补齐protoc-gen-go 如果可以补齐代表成功,如果执行不报错 代表工具成功

3.3 protobuf 简单语法

参考文档(需翻墙):https://developers.google.com/protocol-buffers/docs/proto3

首先看一个简单的例子


syntax = "proto3";  //指定版本信息,不指定会报错
package pb; //后期生成go文件的包名
//message为关键字,作用为定义一种消息类型


// 定义枚举类型
enum Week {
  Monday = 0 ; // 枚举值,必须从 0 开始
  Turesday = 1 ;
}

// 定义消息体
message Person{
  // 可以不从1开始,但不能重复。
  string name = 1 ;
  int32 age = 2 ;
  bool sex = 3;
  // 数组
  repeated string test = 4;
  // 枚举
  Week w = 5 ;
  //联合体
  oneof data {
    string teacher = 6 ;
  }
  map <string,Person> test_map = 7;
}

//消息体可以嵌套
message Home{
  repeated Person persons = 1;
  message V {
    string name = 1;
    string name1 = 2;
    string name2 = 3;
  }
}


  • protobuf消息的定义(或者称为描述)通常都写在一个以.proto结尾的文件中。
  • 该文件的第一行指定正在使用proto3语法:如果不这样做,协议缓冲区编译器将假定正在使用proto2。这也必须是文件的第一个非空的非注释行。
  • 第二行package关键字定义一个Person消息体,类似于go语言中的结构体,是包含一系列类型数据的集合。许多标准的简单数据类型都可以作为字段类型,包括bool,int32,float,double,和string。也可以使用其他message类型作为字段类型。
  • 在message中有一个字符串类型的value成员,该成员编码时用1代替名字。我们知道,在json中是通过成员的名字来绑定对应的数据,但是Protobuf编码却是通过成员的唯一编号来绑定对应的数据,因此Protobuf编码后数据的体积会比较小,能够快速传输,缺点是不利于阅读。

message的格式说明

消息由至少一个字段组合而成,类似于Go语言中的结构体,每个字段都有一定的格式:

//注释格式 注释尽量也写在内容上方
(字段修饰符)数据类型 字段名称 = 唯一的编号标签值;

  • 唯一的编号标签:代表每个字段的一个唯一的编号标签,在同一个消息里不可以重复。这些编号标签用与在消息二进制格式中标识你的字段,并且消息一旦定义就不能更改。 需要说明的是标签在1-15范围的采用一个字节进行编码,所以通常是将标签1-15用于频繁发生的消息字段。 编号标签大小的范围是1-2的29次。19000-19999是官方预留的值,不能使用。
  • 注释格式:向.proto文件添加注释,可以使用C/C++/Java/Go风格的双斜杠(//)语法格式或者//

3.4编写的注意事项!

  • 1、message成员编号,可以不从1开始,但是不能重复。–不能使用19000-19999
  • 2、可以使用message嵌套。
  • 3、定义数组、切片使用repeated关键字
  • 4、 可以使用枚举enum
  • 5、 可以使用联合体。oneof关键字。成员编号,不能重复。

3.5编译protobuf


回顾:c++编译 命令:
protocol --cpp_out=./ *.proto —>xxx.pb.cc 和 xxx.pb.h 文件

  • go 语言中的编译命令
protoc --go_out=./ *proto // --->xxx.pb.go 文件

3.6添加rpc服务

  • 语法
service 服务名 {
	rpc 函数名 (参数:消息体)returns (返回值:消息)
}
message People {
	string name = 1 ;
}
message Student {
	int32 age = 2 ;
}
// 例:
service hello {
	rpc HelloWorld(People) returns (Student);
}
  • 知识点:
    • 默认protobuf,编译期间,不编译服务。要想使之编译。需要使用grpc
    • 使用的编译指令为:
      - protoc --go_out=plugins=grpc:./ *.protoprotoc --go-grpc_out=./ *.proto
  • 生成的xxx.pd.go文件与我们自己封装的rpc对比:

客户端

//--------------grpc
type bj38Client struct {
	cc grpc.ClientConnInterface
}
func NewBj38Client(cc grpc.ClientConnInterface) Bj38Client {
	return &bj38Client{cc}
}
func (c *bj38Client) Say(ctx context.Context, in *Person, opts ...grpc.CallOption) (*Home, error) {
	out := new(Home)
	err := c.cc.Invoke(ctx, "/pb.bj38/Say", in, out, opts...)
	if err != nil {
		return nil, err
	}
	return out, nil
}
//-----------------rpc封装
//1、定义类
type MyClient struct {
	c *rpc.Client	
}
//2、绑定类方法
func (this *MyClient) HelloWorld (a string, b *string) error {
	return this.c.Call("hello.HelloWorld", a, b)	
}
//3、初始化客户端
func Init (addr string) {
	conn,_ := jsonrpc.Dail("tcp", addr)	
}

服务端

//--------------grpc
type Bj38Client interface {
	Say(ctx context.Context, in *Person, opts ...grpc.CallOption) (*Home, error)
}
func RegisterBj38Server(s grpc.ServiceRegistrar, srv Bj38Server) {
	s.RegisterService(&Bj38_ServiceDesc, srv)
}

//-----------------rpc封装
//1、定义接口
type xxx interface {
	方法名(传入参数, 传出参数) error 
}
//例: 
type MyIntercace Interface{
	HelloWorld(string, *string) error
}
//2、封装注册服务方法
func RegisterService (I MyInterface) {
	rpc.RegisterName("hello", I)
}


4、GRPC框架

GRPC是Google公司基于Protobuf开发的跨语言的开源RPC框架。GRPC基于HTTP/2协议设计,可以基于一个HTTP/2链接提供多个服务,对于移动设备更加友好。目前提供C、Java 和Go 语言版本,分别是:grpc, grpc-java,grpc-go.其中C版本支持 C, C++, Node.is, Python, Ruby, Objective-C, PHP 和C#支持.
在gRPC里客户端应用可以像调用本地对象一样直接调用另一台不同的机器上服务端应用的方法,使得您能够更容易地创建分布式应用和服务。与许多 RPC系統类似,gRPC也是基于以下理念:

  • 定义一个服务,指定其能够被远程调用的方法(包含参数和返回类型)。
  • 在服务端实现这个接口,并运行一个 gRPC服务器来处理客户端调用。

在客户端拥有一个存根能够像服务端一样的方法。gRPC客户端和服务端可以在多种环境中运行和交互-从google内部的服务器到你自己的笔记本,并旦可以用任何 gRPC支持的语言来编写。

所以,你可以很容易地用Java创建一个gRPC服务端,用G0、Python、Ruby来创建客户端。此外,Google最新 AP1将有gRPC版本的接口,使你很容易地将 Google的功能集成到你的应用里。

参考资料
gPC 官方文档中文版:http://doc.oschina.net/grpc2t=60133
gRPC官网:https:/lgrpcio

再详细了解使用GRPC之前先来了解一下上面定义中的一些关键词。

首先我们来看一下HTTP/2是什么内容?
其实本质上就是http2.0版本,http目前为止主要有四个版本,分别为http 1.0、 http.1.1、 http2.0、
https.

4.1grpc环境安装

方法1、官方推荐安装方法:

go get -u -v google.golang.org/grpc    -u updata更新。 -v view查看细节

但是由于一些原因,大部分同学不能直接访问google官网

方法2.通过github下载各种依赖库,然后配置。

git clone https://github.com/grpc/grpc-go.git
	$GOPATH/src/google.golang.org/grpc
git clone https://github.com/golang/net.git
	$GOPATH/src/golang.org/x/net
git clone https://github.com/golang/text.git
	$GOPATH/src/golang.org/x/text
git clone https://github.com/google/go-genproto.git
	$GOPATH/src/google.golang.org/genproto
cd $GOPATH/src/ 
go install google.golang.org/grpc

网络畅通可以用上达方法,但如果网速较慢,我们也可以选择离线安装方法。

方法3.用x.zip和 google.golang.org.zip 西介离袋包来安装。

#将x.zip 解压到 $GOPATH/SrC/golang.org/x 目录下
unzip x.zip -d $GOPATH/src/golang.org/x
3 #将google.golang.org.zip解压到 $GOPATH/src/google.golang.org 目录下
unzip google. golang.org. zip -d $GOPATH/src/google. golang.org
5 #然后进入到$GOPATH/srC/ google.golang.org/grpc下面执行go instal1
 go install

4.2GRPC使用

如果从Protobuf的角度看,GRPC只不过是一个针对service接口生成代码的生成器。接着我们来学习一下GRPC的用法。这里我们创建一个简单的proto文件,定义一个HelloService接口:

syntax = "proto3";
package pb;

message Person{
  //名字
  string name = 1 ;
  //年龄
  int32 age = 2 ;
}

//定义RPC服务
service HelloService {
  rpc Hello (Person)returns (Person);
}

对proto文件进行编译:

protoc --go_out=plugins=grpc:. * .proto

作业:grpc远程调用

  • 服务端grpc
    • 1、初始化一个grpc对象
    • 2、注册服务
    • 3、设置监听,指定ip、port
    • 4、启动服务。----serve()
  • 客户端grpc
    • 1、连接grpc服务
    • 2、初始化grpc客户端
    • 3、调用远程服务

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

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

相关文章

[ 数据结构 -- 手撕排序算法第六篇 ] 快速排序

文章目录前言一、常见的排序算法二、快速排序的基本思想三、快速排序的不同实现1.hoare版本2. 挖坑法3. 前后指针法4.三种版本单趟排序结果5.快速排序三数取中优化6.小区间优化四、快速排序的特性总结前言 手撕排序算法第六篇&#xff1a;快速排序&#xff01; 从本篇文章开始…

JavaSE面试题(二)

1&#xff1a;说一说八大基本数据类型 2&#xff1a;面向对象 面向对象的核心&#xff0c;就是类和对象。Java中的面向对象的思想&#xff1a;万物皆对象。 类&#xff1a;是对一类事物的描述&#xff0c;是抽象的&#xff0c;看不见&#xff0c;摸不着。 对象&#xff1a;是实…

week 7 吴恩达 调参 ,batch norm,softmax

文章目录前言7.1调整参数的过程 Turing progress7.2、scale7.3 如果在实践中探寻超参数7.4 batch normalization 批量归一化7.5 将BN算法拟合到神经网络中7.6 为什么 BN有效&#xff1f;7.7测试时的BN7.8 7.9 softmax regression7.10深度学习的框架前言 7.1调整参数的过程 Turi…

CentOS 8:环境变量

环境变量 环境变量&#xff0c;就是放在当前环境中的变量 无论Linux &#xff0c;还是Windows&#xff0c;都有环境变量 比如&#xff0c;最常用的环境变量 PATH, JAVA_HOME 定义环境变量 export JAVA_HOME/opt/jdk1.8 显示环境变量 echo $JAVA_HOME 查看所有环境变量…

c语言位操作和变量存储类型

c语言位操作 c语言变量存储类型 格式[存储类型说明符] 数据类型说明符 变量名&#xff0c;例如&#xff0c;auto int a;但一般情况下auto是省略的 其他类型说明符还有&#xff1a;static 、extern、register auto最普通动态存储&#xff0c;但所在范围的函数程序结束后&#xf…

处理模型视图中的选择

有关在视图中选择的项的信息存储在QItemSelectionModel类中&#xff0c;这将维护单个模型中项的模型索引&#xff0c;并且独立于任何视图。由于一个模型可以有多个视图&#xff0c;因此可以在视图之间共享选择&#xff0c;从而允许应用程序以一致的方式显示多个视图 选择由选…

Redis高并发锁(二)乐观锁

文章目录redis乐观锁1. watch 监控key2. multi 开启事务3. exec 执行事务4. 演示1) 先用两个连接AB访问redis2) A监控key,此时库存是45013) A开启事务&#xff0c;并且将库存-1,事务进入队列等待执行4&#xff09;此时B更新库存为20015&#xff09;A开始执行事务业务改造1. Sto…

C++11--包装器与可变参数摸板

文章目录可变参数模板递归函数方式展开参数包函数包装器举个例子bind函数举个例子可变参数模板 C11的新特性可变参数模板能够让我们创建可以接受可变参数的函数模板和类模板 // Args是一个模板参数包&#xff0c;args是一个函数形参参数包 // 声明一个参数包Args... args&…

Spring Cloud之Feign消费和Hystrix熔断

Spring Cloud的Feign消费和Hystrix熔断 现如今&#xff0c;由于互联网的流行&#xff0c;很多特产都可以在网上订购&#xff0c;你可以在堆满积雪的冬北订购海南的椰子&#xff0c;海南的椰子就会采用很快的物流方式调送到堆满积地的东北&#xff0c;就相当于在本地实现了买椰…

Opencv(C++)笔记--图像金字塔

目录 1--图像金字塔的原理 2--图像金字塔的用途 3--Opencv API 3-1--拉普拉斯金字塔上采样 3-2--高斯金字塔下采样 3-3--代码实例 4--参考 1--图像金字塔的原理 图像金字塔常用于图像缩放&#xff08;resize&#xff09;和图像分割当中&#xff0c;不同分辨率的图像以金…

CSS基础总结(四)浮动

文章目录 一、为什么需要浮动 1.传统网页布局的三种方式 2.标准流 二、浮动的概述 三、浮动的特性 1.脱标 2.一行显示&#xff0c;顶部对齐 3.具备行内块元素特性 四、清除浮动 1.为什么要清除浮动 2.清除浮动的本质与策略 3.清除浮动的四大方法 &#xff08;1&…

解决安卓刷新recyclerView时导致itemDecoration分栏标题绘制错乱(重叠和隔空现象)

安卓的 itemDecoration 装饰器是个好东西&#xff0c;可以与adapter适配器一样闪耀。但是刷新的时候有可能发生重叠绘制或者莫名隔空的BUG。 三、原作 本文分栏标题装饰器的原作者为简书博主endeavor等人&#xff1a; https://www.jianshu.com/p/8a51039d9e68 二、隔空 紧…

Java+MySQL基于ssm的残疾人管理系统

我国残疾人人口数量相当巨大,据中残联给出的数据,我国约有8500万残疾人。残疾人是社会弱势群体,并且数量庞大影响人数众多,如何能更好的对这些残疾人进行关注和帮助他们更好的生活是当下社会研究的一个主要问题之一,于是我们提出了残疾人信息管理系统的设计与开发。 本课题是一…

内核驱动修改内存

概述 本文会利用内核驱动进行读写取第三方应用内存。 内核实现会使用内联汇编 所以对于内核数据结构每个windwos版本不一样需要判断&#xff0c;本文使用19041所写代码。 命令行&#xff1a;winver 即可查看你当前的版本&#xff0c;如下图19042.631 就是构建版本号 或者调用…

痞子衡嵌入式:低功耗高性能边缘人工智能应用的新答案 - MCXN947

大家好&#xff0c;我是痞子衡&#xff0c;是正经搞技术的痞子。今天痞子衡给大家介绍的是恩智浦MCX系列MCU的新品MCXN947。 自 2015 年恩智浦和飞思卡尔合并成新恩智浦之后&#xff0c;关于它们各自的 Arm Cortex-M 内核通用微控制器代表作系列 LPC 和 Kinetis 接下来怎么发展…

数据结构 | 链式二叉树【递归的终极奥义】

递归——这就是俄罗斯套娃吗&#x1f62e;&#x1f333;链式二叉树的结构及其声明&#x1f333;链式二叉树的四种遍历方式&#x1f4d5;先序遍历&#xff08;先根遍历&#xff09;递归算法图解&#x1f4d5;中序遍历&#xff08;中根遍历&#xff09;&#x1f4d5;后序遍历&…

TIA PORTAL 导出导入数据块

1.导出&#xff1a;选择要导出的数据块鼠标右键-->从块生成源-->仅所选块或包含所有关联块-->最后选择数据块的存储路径保存 2.导入&#xff1a;选外部源文件-->添加新的外部文件-->选择要导入的数据块文件-->单击文件鼠标右键-->从源生成块&#xff0c;最…

Vue3——ref(),reactive(),watch(),computed()的使用

都需要先引入才能使用 ref()函数 作用&#xff1a;创建一个响应式变量&#xff0c;使得某个变量在发生改变时可以同步发生在页面上 模板语句中使用这个变量时可以直接使用变量名来调用&#xff0c;在setup内部调用时则需要在变量明后面加上一个.value获取它的值&#xff0c;原…

记录一次使用卷积神经网络进行图片二分类的实战

写在前面 笔者目前就读的专业是软件工程&#xff0c;并非人工智能专业&#xff0c;但是由于对人工智能有兴趣&#xff0c;于是课下进行了一些自学。正巧最近有些闲暇时间&#xff0c;就想着使用自学的内容做个小型的实战。这篇文章的主要目的也就是从一个入门者的角度&#xf…

【C++】list

本期就来讲讲list的使用技巧 文章目录list的介绍及使用list的介绍list迭代器失效list的模拟实现list与vector的对比我们前面知道迭代器是一个像指针一样的东西&#xff0c;但是在C里面&#xff0c;出来string和vector&#xff0c;其他类都不能 将迭代器当成指针使用&#xff0c…