当前位置: 首页 > news >正文

gRPC 非官方教程

一、 简介

gRPC的定义:

  1. 一个高性能、通用的开源RPC框架
  2. 主要面向移动应用开发: gRPC提供了一种简单的方法来精确地定义服务和为iOS、Android和后台支持服务自动生成可靠性很强的客户端功能库。
  3. 基于HTTP/2协议标准而设计,基于ProtoBuf(Protocol Buffers)序列化协议开发
  4. 支持众多开发语言

 

二、 简单rpc调用

主要流程:

  1. 创建maven项目
  2. 添加grpc依赖,protobuf依赖和插件
  3. 通过.proto文件定义服务
  4. 通过protocol buffer compiler插件生成客户端和服务端
  5. 通过grpc API生成客户端和服务端代码

1. 创建maven项目

添加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>vip.sunjin</groupId><artifactId>GrpcServer</artifactId><version>1.0-SNAPSHOT</version><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><java.version>1.8</java.version><grpc.version>1.36.1</grpc.version><protobuf.version>3.15.6</protobuf.version></properties><dependencies><!-- protobuf --><dependency><groupId>com.google.protobuf</groupId><artifactId>protobuf-java</artifactId><version>${protobuf.version}</version></dependency><!-- GRPC --><dependency><groupId>io.grpc</groupId><artifactId>grpc-netty</artifactId><version>${grpc.version}</version></dependency><dependency><groupId>io.grpc</groupId><artifactId>grpc-protobuf</artifactId><version>${grpc.version}</version></dependency><dependency><groupId>io.grpc</groupId><artifactId>grpc-stub</artifactId><version>${grpc.version}</version></dependency></dependencies><build><extensions><extension><groupId>kr.motd.maven</groupId><artifactId>os-maven-plugin</artifactId><version>1.6.2</version></extension></extensions><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin><plugin><groupId>org.xolstice.maven.plugins</groupId><artifactId>protobuf-maven-plugin</artifactId><version>0.6.1</version><configuration><protocArtifact>com.google.protobuf:protoc:3.12.0:exe:${os.detected.classifier}</protocArtifact><pluginId>grpc-java</pluginId><pluginArtifact>io.grpc:protoc-gen-grpc-java:1.36.0:exe:${os.detected.classifier}</pluginArtifact></configuration><executions><execution><goals><goal>compile</goal><goal>compile-custom</goal></goals></execution></executions></plugin></plugins></build></project>

2. 定义RPC服务数据结构 proto文件

创建一个文件夹src/main/proto/

创建一个helloworld.proto文件

syntax = "proto3";option java_multiple_files = true;
option java_package = "vip.sunjin.examples.helloworld";
option java_outer_classname = "HelloWorldProto";package helloworld;// The greeting service definition.
service Greeter {// Sends a greetingrpc SayHello (HelloRequest) returns (HelloReply) {}
}// The request message containing the user's name.
message HelloRequest {string name = 1;
}// The response message containing the greetings
message HelloReply {string message = 1;
}

3. 生成基础类

使用maven编译项目 生成基础类

生成后的类文件如下:

targetclassesvipsunjinexampleshelloworldGreeterGrpc.javaHelloReply.javaHelloReplyOrBuilder.javaHelloRequest.javaHelloRequestOrBuilder.javaHelloWorldClient.javaHelloWorldProto.javaHelloWorldServer.java

GreeterGrpc封装基本的GRPC功能,后续的客户端和服务端都从这个类引申出来。

4. 创建服务端

服务端只需要指定一个端口号,然后暴露一个服务。

/*** Server that manages startup/shutdown of a {@code Greeter} server.*/
public class HelloWorldServer {private static final Logger logger = Logger.getLogger(HelloWorldServer.class.getName());private Server server;private void start() throws IOException {/* The port on which the server should run */int port = 50051;server = ServerBuilder.forPort(port).addService(new GreeterImpl()).build().start();logger.info("Server started, listening on " + port);Runtime.getRuntime().addShutdownHook(new Thread() {@Overridepublic void run() {// Use stderr here since the logger may have been reset by its JVM shutdown hook.System.err.println("*** shutting down gRPC server since JVM is shutting down");try {HelloWorldServer.this.stop();} catch (InterruptedException e) {e.printStackTrace(System.err);}System.err.println("*** server shut down");}});}private void stop() throws InterruptedException {if (server != null) {server.shutdown().awaitTermination(30, TimeUnit.SECONDS);}}/*** Await termination on the main thread since the grpc library uses daemon threads.*/private void blockUntilShutdown() throws InterruptedException {if (server != null) {server.awaitTermination();}}/*** Main launches the server from the command line.*/public static void main(String[] args) throws IOException, InterruptedException {final HelloWorldServer server = new HelloWorldServer();server.start();server.blockUntilShutdown();}static class GreeterImpl extends GreeterGrpc.GreeterImplBase {@Overridepublic void sayHello(HelloRequest req, StreamObserver<HelloReply> responseObserver) {HelloReply reply = HelloReply.newBuilder().setMessage("Hello " + req.getName()).build();responseObserver.onNext(reply);responseObserver.onCompleted();}}
}

5. 创建客户端

客户端需要指定调用服务的地址和端口号并且通过调用桩代码调用服务端的服务。

客户端和服务端是直连的。

public class HelloWorldClient {private static final Logger logger = Logger.getLogger(HelloWorldClient.class.getName());private final GreeterGrpc.GreeterBlockingStub blockingStub;/** Construct client for accessing HelloWorld server using the existing channel. */public HelloWorldClient(Channel channel) {// 'channel' here is a Channel, not a ManagedChannel, so it is not this code's responsibility to// shut it down.// Passing Channels to code makes code easier to test and makes it easier to reuse Channels.blockingStub = GreeterGrpc.newBlockingStub(channel);}/** Say hello to server. */public void greet(String name) {logger.info("Will try to greet " + name + " ...");HelloRequest request = HelloRequest.newBuilder().setName(name).build();HelloReply response;try {response = blockingStub.sayHello(request);} catch (StatusRuntimeException e) {logger.log(Level.WARNING, "RPC failed: {0}", e.getStatus());return;}logger.info("Greeting Reply: " + response.getMessage());}/*** Greet server. If provided, the first element of {@code args} is the name to use in the* greeting. The second argument is the target server.*/public static void main(String[] args) throws Exception {String user = "neil";// Access a service running on the local machine on port 50051String target = "localhost:50051";// Create a communication channel to the server, known as a Channel. Channels are thread-safe// and reusable. It is common to create channels at the beginning of your application and reuse// them until the application shuts down.ManagedChannel channel = ManagedChannelBuilder.forTarget(target)// Channels are secure by default (via SSL/TLS). For the example we disable TLS to avoid// needing certificates..usePlaintext().build();try {HelloWorldClient client = new HelloWorldClient(channel);client.greet(user);} finally {// ManagedChannels use resources like threads and TCP connections. To prevent leaking these// resources the channel should be shut down when it will no longer be used. If it may be used// again leave it running.channel.shutdownNow().awaitTermination(5, TimeUnit.SECONDS);}}
}

6. 测试

先启动服务端代码 HelloWorldServer

然后执行客户端代码 HelloWorldClient

执行结果如下:

2月 18, 2023 9:44:17 上午 vip.sunjin.grpcclient.HelloWorldClient greet
信息: Will try to greet neil ...
2月 18, 2023 9:44:18 上午 vip.sunjin.grpcclient.HelloWorldClient greet
信息: Greeting Reply: I'm Grpc Server , Hello neil

三、 grpc服务端流

一般业务场景下,我们都是使用grpc的simple-rpc模式,也就是每次客户端发起请求,服务端会返回一个响应结果的模式。

但是grpc除了这种一来一往的请求模式外,还有流式模式。

服务端流模式是说客户端发起一次请求后,服务端在接受到请求后,可以以流的方式,使用同一连接,不断的向客户端写回响应结果,客户端则可以源源不断的接受到服务端写回的数据。

下面我们通过简单例子,来说明如何使用,服务端端流。

1. 定义RPC服务数据结构 proto文件

MetricsService.proto

syntax = "proto3";option java_multiple_files = true;
option java_package = "vip.sunjin.examples.helloworld";
option java_outer_classname = "MetricsServiceProto";message Metric {int64 metric = 2;
}message Average {double val = 1;
}service MetricsService {rpc collectServerStream (Metric) returns (stream Average);
}

然后使用maven编译项目 生成基础类

2.创建服务端代码

服务实现类

public class MetricsServiceImpl extends MetricsServiceGrpc.MetricsServiceImplBase {private static final Logger logger = Logger.getLogger(MetricsServiceImpl.class.getName());/*** 服务端流* @param request* @param responseObserver*/@Overridepublic void collectServerStream(Metric request, StreamObserver<Average> responseObserver) {logger.info("received request : " +  request.getMetric());for(int i = 0; i  < 10; i++){responseObserver.onNext(Average.newBuilder().setVal(new Random(1000).nextDouble()).build());logger.info("send to client");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}responseObserver.onCompleted();}}

服务端Server启动类

public class MetricsServer {private static final Logger logger = Logger.getLogger(MetricsServer.class.getName());public static void main(String[] args) throws IOException, InterruptedException {int port = 50051;
//        //启动服务MetricsServiceImpl metricsService = new MetricsServiceImpl();Server server = ServerBuilder.forPort(port).addService(metricsService).build();server.start();logger.info("Server started, listening on " + port);server.awaitTermination();}
}

3.创建客户端代码

通过异步Stub 调用服务

public class MetricsClient {private static final Logger logger = Logger.getLogger(MetricsClient.class.getName());public static void main(String[] args) throws InterruptedException {int port = 50051;
//        //获取客户端桩对象ManagedChannel channel = ManagedChannelBuilder.forTarget("localhost:" + port).usePlaintext().build();MetricsServiceGrpc.MetricsServiceStub stub = MetricsServiceGrpc.newStub(channel);//发起rpc请求,设置StreamObserver用于监听服务器返回结果stub.collectServerStream(Metric.newBuilder().setMetric(1L).build(), new StreamObserver<Average>() {@Overridepublic void onNext(Average value) {System.out.println(Thread.currentThread().getName() + "Average: " + value.getVal());}@Overridepublic void onError(Throwable t) {System.out.println("error:" + t.getLocalizedMessage());}@Overridepublic void onCompleted() {System.out.println("onCompleted:");}});channel.shutdown().awaitTermination(50, TimeUnit.SECONDS);}
}

代码最后要有等待并且关闭通道的操作。

4.测试

先启动服务端,再启动客户端后,可以看到StreamObserver的onNext方法会源源不断的接受到服务端返回的数据。

5,服务端流使用场景:

  • 客户端请求一次,但是需要服务端源源不断的返回大量数据时候,比如大批量数据查询的场景。
  • 比如客户端订阅服务端的一个服务数据,服务端发现有新数据时,源源不断的吧数据推送给客户端。

四、 grpc客户端流

客户端流模式是说客户端发起请求与服务端建立链接后,可以使用同一连接,不断的向服务端传送数据,等客户端把全部数据都传送完毕后,服务端才返回一个请求结果。

1. 定义RPC服务数据结构 proto文件

这里修改service的定义,其他不变。 MetricsService.proto

service MetricsService {rpc collectClientStream (stream Metric) returns (Average);
}

2.创建服务端代码

如上rpc方法的入参类型前添加stream标识 是客户端流,然后服务端实现代码如下:

public class MetricsServiceImpl extends MetricsServiceGrpc.MetricsServiceImplBase {private static final Logger logger = Logger.getLogger(MetricsServiceImpl.class.getName());/*** 客户端流** @param responseObserver* @return*/@Overridepublic StreamObserver<Metric> collectClientStream(StreamObserver<Average> responseObserver) {return new StreamObserver<Metric>() {private long sum = 0;private long count = 0;@Overridepublic void onNext(Metric value) {logger.info("value: " + value);sum += value.getMetric();count++;}@Overridepublic void onError(Throwable t) {logger.info("severError:" + t.getLocalizedMessage());responseObserver.onError(t);}@Overridepublic void onCompleted() {responseObserver.onNext(Average.newBuilder().setVal(sum / count).build());logger.info("serverComplete: ");responseObserver.onCompleted();}};}
}

如上代码,服务端使用流式对象的onNext方法不断接受客户端发来的数据,然后等客户端发送结束后,使用onCompleted方法,把响应结果写回客户端。

服务端启动类MetricsServer不需要修改

3.创建客户端代码

客户端调用服务需要使用异步的Stub.

public class MetricsClient2 {private static final Logger logger = Logger.getLogger(MetricsServer.class.getName());public static void main(String[] args) throws InterruptedException {int port = 50051;//1.创建客户端桩ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", port).usePlaintext().build();MetricsServiceGrpc.MetricsServiceStub stub = MetricsServiceGrpc.newStub(channel);//2.发起请求,并设置结果回调监听StreamObserver<Metric> collect = stub.collectClientStream(new StreamObserver<Average>() {@Overridepublic void onNext(Average value) {logger.info(Thread.currentThread().getName() + "Average: " + value.getVal());}@Overridepublic void onError(Throwable t) {logger.info("error:" + t.getLocalizedMessage());}@Overridepublic void onCompleted() {logger.info("onCompleted:");}});//3.使用同一个链接,不断向服务端传送数据Stream.of(1L, 2L, 3L, 4L,5L).map(l -> Metric.newBuilder().setMetric(l).build()).forEach(metric -> {collect.onNext(metric);logger.info("send to server: " + metric.getMetric());});Thread.sleep(3000);collect.onCompleted();channel.shutdown().awaitTermination(50, TimeUnit.SECONDS);}
}

4.测试

先启动服务端,再启动客户端后,可以看到代码3会把数据1,2,3,4,5通过同一个链接发送到服务端, 然后等服务端接收完毕数据后,会计算接受到的数据的平均值,然后把平均值写回客户端。 然后代码2设置的监听器的onNext方法就会被回调,然后打印出服务端返回的平均值3。

5,客户端流使用场景:

  • 比如数据批量计算场景:如果只用simple rpc的话,服务端就要一次性收到大量数据,并且在收到全部数据之后才能对数据进行计算处理。如果用客户端流 rpc的话,服务端可以在收到一些记录之后就开始处理,也更有实时性。

五、grpc双向流

双向流意味着客户端向服务端发起请求后,客户端可以源源不断向服务端写入数据的同时,服务端可以源源不断向客户端写入数据。

1. 定义RPC服务数据结构 proto文件

这里修改service的定义,其他不变。 重新生成基础代码。 MetricsService.proto

service MetricsService {rpc collectTwoWayStream (stream Metric) returns (stream Average);
}

如上rpc方法的入参类型前添加stream标识, 返回参数前也添加stream标识 就是双向流,然后服务端实现代码如下:

双向流的代码和客户端流基本一样,只是双向流可以同时支持双向的持续写入。

2.创建服务端代码

将服务实现类进行修改用来测试双向流。

public void onNext(Metric value) {logger.info("value: " + value);sum += value.getMetric();count++;responseObserver.onNext(Average.newBuilder().setVal(sum * 1.0/ count).build());
}

如上代码,服务端使用流式对象的onNext方法不断接受客户端发来的数据, 然后 不断的调用参数中的流对象把响应结果持续的写回客户端。 实现了双向流式调用。

3.创建客户端代码

客户端代码主要是把onCompleted之前的线程等待时间加长,以便等待服务端持续的返回。

Thread.sleep(10000);
collect.onCompleted();

4.测试

先启动服务端,再启动客户端后,可以看到代码3会把数据1,2,3,4,5通过同一个链接发送到服务端, 然后等服务端接收数据后,会实时的计算接受到的数据的平均值,然后把平均值写回客户端。 然后代码2设置的监听器的onNext方法就会被回调,然后打印出服务端返回的平均值。

相关文章:

gRPC 非官方教程

一、 简介 gRPC的定义&#xff1a; 一个高性能、通用的开源RPC框架主要面向移动应用开发&#xff1a; gRPC提供了一种简单的方法来精确地定义服务和为iOS、Android和后台支持服务自动生成可靠性很强的客户端功能库。基于HTTP/2协议标准而设计&#xff0c;基于ProtoBuf(Protoc…...

6.2【人工智能与深度学习】RNN、GRU、远程服务管理、注意力、Seq2 搜索引擎和内存网络

【人工智能与深度学习】RNN、GRU、远程服务管理、注意力、Seq2 搜索引擎和内存网络底层原理介绍 深度学习架构循环神经网络(RNN)循环网络:摊开循环的网络的循环循环神经网络的技巧乘法模组注意模组门控循环单元(GRU)长期短期记忆(Long Short-Term Memory,简称LSTM)序列到序列…...

软件工程复习

软件工程简介 软件&#xff1a; -在执行时提供所需的功能和性能的指令&#xff1b; -使程序能够充分操作信息的数据结构&#xff1b; -描述这些程序的操作和使用情况的文档。 软件定义&#xff1a;计算机程序和相关文档。 软件特点&#xff1a;软件没有质量&#xff1b;它并不…...

将Nginx 核心知识点扒了个底朝天(二)

Nginx 是如何实现高并发的&#xff1f; 如果一个 server 采用一个进程(或者线程)负责一个request的方式&#xff0c;那么进程数就是并发数。那么显而易见的&#xff0c;就是会有很多进程在等待中。等什么&#xff1f;最多的应该是等待网络传输。 而 Nginx 的异步非阻塞工作方…...

【PowerQuery】PowerBI 的PowerQuery支持的数据集成

PowerBI中的各个Power组件已经被深度集成到PowerBI中,不再作为像Excel一样的独立组件而存在。在PowerBI的界面中为了快速导入这些常用的数据,也有相应的快速导入界面。PowerBI的快速导入界面位于主页面中,下图就是PowerBI的快速导入界面。 在PowerBI中的数据导入界面相比Exc…...

scipy spatial transform Rotation库的源代码

前几日研究scipy的旋转&#xff0c;不知道具体里面怎么实现的&#xff0c;因此搜索一番。 发现Rotation在scipy的表达是用四元数的 https://github.com/jgagneastro/coffeegrindsize/edit/master/App/dist/coffeegrindsize.app/Contents/Resources/lib/python3.7/scipy/spatia…...

JAVA文件操作

JAVA文件操作 文章目录JAVA文件操作1.属性2.构造方法3.方法3.1创建文件3.2 文件删除3.3创建目录3.4文件名3.5 文件重命名3.6查看文件的可读性​ Java中通过 java.io.file类来对文件(目录)进行抽象的描述。注意&#xff0c; 有File对象时&#xff0c;不代表真实存在该文件。1.属…...

字符串匹配 - 模式预处理:BM 算法 (Boyer-Moore)

各种文本编辑器的"查找"功能&#xff08;CtrlF&#xff09;&#xff0c;大多采用Boyer-Moore算法&#xff0c;效率非常高。算法简介在 1977 年&#xff0c;Robert S. Boyer (Stanford Research Institute) 和 J Strother Moore (Xerox Palo Alto Research Center) 共…...

RV1126笔记三十:freetype显示矢量字体

若该文为原创文章,转载请注明原文出处。 在前面介绍了使用取模软件,可以自定义OSD,这种做法相对不灵活,也无法变更,适用大部分场景。 如果使用opencv需要移植opencv,芯片资源相对要相比好,而且移植比freetype复杂。 这里记录下如何使用freetype显示矢量字体,使用fre…...

polkit pkexec 本地提权漏洞修复方案

polkit pkexec 本地提权漏洞 漏洞细节&#xff0c;polkit pkexec 中对命令行参数处理有误&#xff0c;导致参数注入&#xff0c;能够导致本地提权。 解决建议 1、无法升级软件修复包的&#xff0c;可使用以下命令删除pkexec的SUID-bit权限来规避漏洞风险&#xff1a; chmod 0…...

es-06聚合查询

聚合查询 概念 聚合&#xff08;aggs&#xff09;不同于普通查询&#xff0c;是目前学到的第二种大的查询分类&#xff0c;第一种即“query”&#xff0c;因此在代码中的第一层嵌套由“query”变为了“aggs”。用于进行聚合的字段必须是exact value&#xff0c;分词字段不可进行…...

面试知识点准备与总结——(并发篇)

目录线程有哪些状态线程池的核心参数sleep和wait的区别lock 与 synchronized 的异同volatile能否保证线程安全悲观锁和乐观锁的区别Hashtable 与 ConcurrentHashMap 的区别ConcurrentHashMap1.7和1.8的区别ThreadLocal的理解ThreadLocalMap中的key为何要设置为弱引用线程有哪些…...

Django框架之模型视图-URLconf

URLconf 浏览者通过在浏览器的地址栏中输入网址请求网站对于Django开发的网站&#xff0c;由哪一个视图进行处理请求&#xff0c;是由url匹配找到的 配置URLconf 1.settings.py中 指定url配置 ROOT_URLCONF 项目.urls2.项目中urls.py 匹配成功后&#xff0c;包含到应用的urls…...

操作系统闲谈06——进程管理

操作系统闲谈06——进程管理 一、进程调度 01 时间片轮转 给每一个进程分配一个时间片&#xff0c;然后时间片用完了&#xff0c;把cpu分配给另一个进程 时间片通常设置为 20ms ~ 50ms 02 先来先服务 就是维护了一个就绪队列&#xff0c;每次选择最先进入队列的进程&#…...

DaVinci 偏好设置:用户 - UI 设置

偏好设置 - 用户/ UI 设置Preferences - User/ UI Settings工作区选项Workspace Options语言Language指定 DaVinci Resolve 软件界面所使用的语言。目前支持英语、简体中文、日语、西班牙语、葡萄牙语、法语、俄语、泰语和越南语等等。启动时重新加载上一个工作项目Reload last…...

Nacos超简单-管理配置文件

优点理论什么的就不说了&#xff0c;按照流程开始配配置吧。登录Centos&#xff0c;启动Naocs&#xff0c;使用sh /data/soft/restart.sh将自动启动Nacos。访问&#xff1a;http://192.168.101.65:8848/nacos/账号密码&#xff1a;nacos/nacos分为两部分&#xff0c;第一部分准…...

基于微信小程序的中国各地美食推荐平台小程序

文末联系获取源码 开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7/8.0 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a;Maven3.3.…...

如何优雅的导出函数

在开发过程中&#xff0c;经常会引用外部函数。方法主要有两种&#xff1a; 方法一&#xff1a;包含头文件并制定lib位置 优点&#xff1a;使用简单缺点&#xff1a;lib和vs版本有关&#xff0c;不同的版本和编译模式可能导致编译失败 方法二&#xff1a;GetProcAddress 优…...

c++多重继承

1.概论多重继承是否有必要吗&#xff1f;这个问题显然是一个哲学问题&#xff0c;正确的解答方式是根据情况来看&#xff0c;有时候需要&#xff0c;有时候不需要&#xff0c;这显然是一句废话&#xff0c;有点像上马克思主义哲学或者中庸思。但是这个问题和那些思想一样&#…...

15_FreeRtos计数信号量优先级翻转互斥信号量

目录 计数型信号量 计数型信号量相关API函数 计数型信号量实验源码 优先级翻转简介 优先级翻转实验源码 互斥信号量 互斥信号量相关API函数 互斥信号量实验源码 计数型信号量 计数型信号量相当于队列长度大于1的队列&#xff0c;因此计数型信号量能够容纳多个资源,这在…...

挑战杯推荐项目

“人工智能”创意赛 - 智能艺术创作助手&#xff1a;借助大模型技术&#xff0c;开发能根据用户输入的主题、风格等要求&#xff0c;生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用&#xff0c;帮助艺术家和创意爱好者激发创意、提高创作效率。 ​ - 个性化梦境…...

Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例

使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件&#xff0c;常用于在两个集合之间进行数据转移&#xff0c;如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model&#xff1a;绑定右侧列表的值&…...

dedecms 织梦自定义表单留言增加ajax验证码功能

增加ajax功能模块&#xff0c;用户不点击提交按钮&#xff0c;只要输入框失去焦点&#xff0c;就会提前提示验证码是否正确。 一&#xff0c;模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...

MMaDA: Multimodal Large Diffusion Language Models

CODE &#xff1a; https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA&#xff0c;它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构&#xf…...

Ascend NPU上适配Step-Audio模型

1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统&#xff0c;支持多语言对话&#xff08;如 中文&#xff0c;英文&#xff0c;日语&#xff09;&#xff0c;语音情感&#xff08;如 开心&#xff0c;悲伤&#xff09;&#x…...

NLP学习路线图(二十三):长短期记忆网络(LSTM)

在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...

怎么让Comfyui导出的图像不包含工作流信息,

为了数据安全&#xff0c;让Comfyui导出的图像不包含工作流信息&#xff0c;导出的图像就不会拖到comfyui中加载出来工作流。 ComfyUI的目录下node.py 直接移除 pnginfo&#xff08;推荐&#xff09;​​ 在 save_images 方法中&#xff0c;​​删除或注释掉所有与 metadata …...

如何应对敏捷转型中的团队阻力

应对敏捷转型中的团队阻力需要明确沟通敏捷转型目的、提升团队参与感、提供充分的培训与支持、逐步推进敏捷实践、建立清晰的奖励和反馈机制。其中&#xff0c;明确沟通敏捷转型目的尤为关键&#xff0c;团队成员只有清晰理解转型背后的原因和利益&#xff0c;才能降低对变化的…...

Kafka主题运维全指南:从基础配置到故障处理

#作者&#xff1a;张桐瑞 文章目录 主题日常管理1. 修改主题分区。2. 修改主题级别参数。3. 变更副本数。4. 修改主题限速。5.主题分区迁移。6. 常见主题错误处理常见错误1&#xff1a;主题删除失败。常见错误2&#xff1a;__consumer_offsets占用太多的磁盘。 主题日常管理 …...

Docker拉取MySQL后数据库连接失败的解决方案

在使用Docker部署MySQL时&#xff0c;拉取并启动容器后&#xff0c;有时可能会遇到数据库连接失败的问题。这种问题可能由多种原因导致&#xff0c;包括配置错误、网络设置问题、权限问题等。本文将分析可能的原因&#xff0c;并提供解决方案。 一、确认MySQL容器的运行状态 …...