GRPC的四种数据流:

1、简单模式(Simple RPC)

2、服务端数据流模式(Server-side Streaming RPC)

3、客户端数据流模式(Client-side Streaming RPC)

4、双向数据流模式(Bidirectional Streaming RPC)

如果对GRPC和protobuf不了解的话,可以参看一下文章:

protobuf与grpc_天龙至尊的博客-CSDN博客这里介绍protobuf的工具的下载与使用,以及结合grpc进行微服务框架的编写!!!protoc的程序的下载链接如下:Releases · protocolbuffers/protobuf · GitHubProtocol Buffers - Google's data interchange format - Releases · protocolbuffers/protobufhttps://github.com/protocolbuffers/protobuf/releases选择对应的操作系统类型https://wtl4it.blog.csdn.net/article/details/125571923?spm=1001.2014.3001.5502stream.proto:

syntax = "proto3";option go_package = "./;grpc_proto";service Stream {rpc GetStream(StreamRequestData) returns (stream StreamResponseData);rpc PutStream(stream StreamRequestData) returns (StreamResponseData);rpc AllStream(stream StreamRequestData) returns (stream StreamResponseData);
}message StreamRequestData {string data = 1;
}message StreamResponseData {string data = 1;
}

执行命令,进行grpc代码的生成:

stream.pb.go:

// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
//  protoc-gen-go v1.26.0
//  protoc        v3.21.2
// source: stream.protopackage grpc_protoimport (context "context"grpc "google.golang.org/grpc"codes "google.golang.org/grpc/codes"status "google.golang.org/grpc/status"protoreflect "google.golang.org/protobuf/reflect/protoreflect"protoimpl "google.golang.org/protobuf/runtime/protoimpl"reflect "reflect"sync "sync"
)const (// Verify that this generated code is sufficiently up-to-date._ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)// Verify that runtime/protoimpl is sufficiently up-to-date._ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)type StreamRequestData struct {state         protoimpl.MessageStatesizeCache     protoimpl.SizeCacheunknownFields protoimpl.UnknownFieldsData string `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
}func (x *StreamRequestData) Reset() {*x = StreamRequestData{}if protoimpl.UnsafeEnabled {mi := &file_stream_proto_msgTypes[0]ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))ms.StoreMessageInfo(mi)}
}func (x *StreamRequestData) String() string {return protoimpl.X.MessageStringOf(x)
}func (*StreamRequestData) ProtoMessage() {}func (x *StreamRequestData) ProtoReflect() protoreflect.Message {mi := &file_stream_proto_msgTypes[0]if protoimpl.UnsafeEnabled && x != nil {ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))if ms.LoadMessageInfo() == nil {ms.StoreMessageInfo(mi)}return ms}return mi.MessageOf(x)
}// Deprecated: Use StreamRequestData.ProtoReflect.Descriptor instead.
func (*StreamRequestData) Descriptor() ([]byte, []int) {return file_stream_proto_rawDescGZIP(), []int{0}
}func (x *StreamRequestData) GetData() string {if x != nil {return x.Data}return ""
}type StreamResponseData struct {state         protoimpl.MessageStatesizeCache     protoimpl.SizeCacheunknownFields protoimpl.UnknownFieldsData string `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
}func (x *StreamResponseData) Reset() {*x = StreamResponseData{}if protoimpl.UnsafeEnabled {mi := &file_stream_proto_msgTypes[1]ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))ms.StoreMessageInfo(mi)}
}func (x *StreamResponseData) String() string {return protoimpl.X.MessageStringOf(x)
}func (*StreamResponseData) ProtoMessage() {}func (x *StreamResponseData) ProtoReflect() protoreflect.Message {mi := &file_stream_proto_msgTypes[1]if protoimpl.UnsafeEnabled && x != nil {ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))if ms.LoadMessageInfo() == nil {ms.StoreMessageInfo(mi)}return ms}return mi.MessageOf(x)
}// Deprecated: Use StreamResponseData.ProtoReflect.Descriptor instead.
func (*StreamResponseData) Descriptor() ([]byte, []int) {return file_stream_proto_rawDescGZIP(), []int{1}
}func (x *StreamResponseData) GetData() string {if x != nil {return x.Data}return ""
}var File_stream_proto protoreflect.FileDescriptorvar file_stream_proto_rawDesc = []byte{0x0a, 0x0c, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x27,0x0a, 0x11, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x44,0x61, 0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28,0x09, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x28, 0x0a, 0x12, 0x53, 0x74, 0x72, 0x65, 0x61,0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12, 0x12, 0x0a,0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x61, 0x74,0x61, 0x32, 0xb2, 0x01, 0x0a, 0x06, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x36, 0x0a, 0x09,0x47, 0x65, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x12, 0x2e, 0x53, 0x74, 0x72, 0x65,0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x1a, 0x13, 0x2e,0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x44, 0x61,0x74, 0x61, 0x30, 0x01, 0x12, 0x36, 0x0a, 0x09, 0x50, 0x75, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61,0x6d, 0x12, 0x12, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,0x74, 0x44, 0x61, 0x74, 0x61, 0x1a, 0x13, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65,0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x44, 0x61, 0x74, 0x61, 0x28, 0x01, 0x12, 0x38, 0x0a, 0x09,0x41, 0x6c, 0x6c, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x12, 0x2e, 0x53, 0x74, 0x72, 0x65,0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x1a, 0x13, 0x2e,0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x44, 0x61,0x74, 0x61, 0x28, 0x01, 0x30, 0x01, 0x42, 0x0f, 0x5a, 0x0d, 0x2e, 0x2f, 0x3b, 0x67, 0x72, 0x70,0x63, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}var (file_stream_proto_rawDescOnce sync.Oncefile_stream_proto_rawDescData = file_stream_proto_rawDesc
)func file_stream_proto_rawDescGZIP() []byte {file_stream_proto_rawDescOnce.Do(func() {file_stream_proto_rawDescData = protoimpl.X.CompressGZIP(file_stream_proto_rawDescData)})return file_stream_proto_rawDescData
}var file_stream_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_stream_proto_goTypes = []interface{}{(*StreamRequestData)(nil),  // 0: StreamRequestData(*StreamResponseData)(nil), // 1: StreamResponseData
}
var file_stream_proto_depIdxs = []int32{0, // 0: Stream.GetStream:input_type -> StreamRequestData0, // 1: Stream.PutStream:input_type -> StreamRequestData0, // 2: Stream.AllStream:input_type -> StreamRequestData1, // 3: Stream.GetStream:output_type -> StreamResponseData1, // 4: Stream.PutStream:output_type -> StreamResponseData1, // 5: Stream.AllStream:output_type -> StreamResponseData3, // [3:6] is the sub-list for method output_type0, // [0:3] is the sub-list for method input_type0, // [0:0] is the sub-list for extension type_name0, // [0:0] is the sub-list for extension extendee0, // [0:0] is the sub-list for field type_name
}func init() { file_stream_proto_init() }
func file_stream_proto_init() {if File_stream_proto != nil {return}if !protoimpl.UnsafeEnabled {file_stream_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {switch v := v.(*StreamRequestData); i {case 0:return &v.statecase 1:return &v.sizeCachecase 2:return &v.unknownFieldsdefault:return nil}}file_stream_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {switch v := v.(*StreamResponseData); i {case 0:return &v.statecase 1:return &v.sizeCachecase 2:return &v.unknownFieldsdefault:return nil}}}type x struct{}out := protoimpl.TypeBuilder{File: protoimpl.DescBuilder{GoPackagePath: reflect.TypeOf(x{}).PkgPath(),RawDescriptor: file_stream_proto_rawDesc,NumEnums:      0,NumMessages:   2,NumExtensions: 0,NumServices:   1,},GoTypes:           file_stream_proto_goTypes,DependencyIndexes: file_stream_proto_depIdxs,MessageInfos:      file_stream_proto_msgTypes,}.Build()File_stream_proto = out.Filefile_stream_proto_rawDesc = nilfile_stream_proto_goTypes = nilfile_stream_proto_depIdxs = nil
}// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ grpc.ClientConnInterface// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion6// StreamClient is the client API for Stream service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type StreamClient interface {GetStream(ctx context.Context, in *StreamRequestData, opts ...grpc.CallOption) (Stream_GetStreamClient, error)PutStream(ctx context.Context, opts ...grpc.CallOption) (Stream_PutStreamClient, error)AllStream(ctx context.Context, opts ...grpc.CallOption) (Stream_AllStreamClient, error)
}type streamClient struct {cc grpc.ClientConnInterface
}func NewStreamClient(cc grpc.ClientConnInterface) StreamClient {return &streamClient{cc}
}func (c *streamClient) GetStream(ctx context.Context, in *StreamRequestData, opts ...grpc.CallOption) (Stream_GetStreamClient, error) {stream, err := c.cc.NewStream(ctx, &_Stream_serviceDesc.Streams[0], "/Stream/GetStream", opts...)if err != nil {return nil, err}x := &streamGetStreamClient{stream}if err := x.ClientStream.SendMsg(in); err != nil {return nil, err}if err := x.ClientStream.CloseSend(); err != nil {return nil, err}return x, nil
}type Stream_GetStreamClient interface {Recv() (*StreamResponseData, error)grpc.ClientStream
}type streamGetStreamClient struct {grpc.ClientStream
}func (x *streamGetStreamClient) Recv() (*StreamResponseData, error) {m := new(StreamResponseData)if err := x.ClientStream.RecvMsg(m); err != nil {return nil, err}return m, nil
}func (c *streamClient) PutStream(ctx context.Context, opts ...grpc.CallOption) (Stream_PutStreamClient, error) {stream, err := c.cc.NewStream(ctx, &_Stream_serviceDesc.Streams[1], "/Stream/PutStream", opts...)if err != nil {return nil, err}x := &streamPutStreamClient{stream}return x, nil
}type Stream_PutStreamClient interface {Send(*StreamRequestData) errorCloseAndRecv() (*StreamResponseData, error)grpc.ClientStream
}type streamPutStreamClient struct {grpc.ClientStream
}func (x *streamPutStreamClient) Send(m *StreamRequestData) error {return x.ClientStream.SendMsg(m)
}func (x *streamPutStreamClient) CloseAndRecv() (*StreamResponseData, error) {if err := x.ClientStream.CloseSend(); err != nil {return nil, err}m := new(StreamResponseData)if err := x.ClientStream.RecvMsg(m); err != nil {return nil, err}return m, nil
}func (c *streamClient) AllStream(ctx context.Context, opts ...grpc.CallOption) (Stream_AllStreamClient, error) {stream, err := c.cc.NewStream(ctx, &_Stream_serviceDesc.Streams[2], "/Stream/AllStream", opts...)if err != nil {return nil, err}x := &streamAllStreamClient{stream}return x, nil
}type Stream_AllStreamClient interface {Send(*StreamRequestData) errorRecv() (*StreamResponseData, error)grpc.ClientStream
}type streamAllStreamClient struct {grpc.ClientStream
}func (x *streamAllStreamClient) Send(m *StreamRequestData) error {return x.ClientStream.SendMsg(m)
}func (x *streamAllStreamClient) Recv() (*StreamResponseData, error) {m := new(StreamResponseData)if err := x.ClientStream.RecvMsg(m); err != nil {return nil, err}return m, nil
}// StreamServer is the server API for Stream service.
type StreamServer interface {GetStream(*StreamRequestData, Stream_GetStreamServer) errorPutStream(Stream_PutStreamServer) errorAllStream(Stream_AllStreamServer) error
}// UnimplementedStreamServer can be embedded to have forward compatible implementations.
type UnimplementedStreamServer struct {
}func (*UnimplementedStreamServer) GetStream(*StreamRequestData, Stream_GetStreamServer) error {return status.Errorf(codes.Unimplemented, "method GetStream not implemented")
}
func (*UnimplementedStreamServer) PutStream(Stream_PutStreamServer) error {return status.Errorf(codes.Unimplemented, "method PutStream not implemented")
}
func (*UnimplementedStreamServer) AllStream(Stream_AllStreamServer) error {return status.Errorf(codes.Unimplemented, "method AllStream not implemented")
}func RegisterStreamServer(s *grpc.Server, srv StreamServer) {s.RegisterService(&_Stream_serviceDesc, srv)
}func _Stream_GetStream_Handler(srv interface{}, stream grpc.ServerStream) error {m := new(StreamRequestData)if err := stream.RecvMsg(m); err != nil {return err}return srv.(StreamServer).GetStream(m, &streamGetStreamServer{stream})
}type Stream_GetStreamServer interface {Send(*StreamResponseData) errorgrpc.ServerStream
}type streamGetStreamServer struct {grpc.ServerStream
}func (x *streamGetStreamServer) Send(m *StreamResponseData) error {return x.ServerStream.SendMsg(m)
}func _Stream_PutStream_Handler(srv interface{}, stream grpc.ServerStream) error {return srv.(StreamServer).PutStream(&streamPutStreamServer{stream})
}type Stream_PutStreamServer interface {SendAndClose(*StreamResponseData) errorRecv() (*StreamRequestData, error)grpc.ServerStream
}type streamPutStreamServer struct {grpc.ServerStream
}func (x *streamPutStreamServer) SendAndClose(m *StreamResponseData) error {return x.ServerStream.SendMsg(m)
}func (x *streamPutStreamServer) Recv() (*StreamRequestData, error) {m := new(StreamRequestData)if err := x.ServerStream.RecvMsg(m); err != nil {return nil, err}return m, nil
}func _Stream_AllStream_Handler(srv interface{}, stream grpc.ServerStream) error {return srv.(StreamServer).AllStream(&streamAllStreamServer{stream})
}type Stream_AllStreamServer interface {Send(*StreamResponseData) errorRecv() (*StreamRequestData, error)grpc.ServerStream
}type streamAllStreamServer struct {grpc.ServerStream
}func (x *streamAllStreamServer) Send(m *StreamResponseData) error {return x.ServerStream.SendMsg(m)
}func (x *streamAllStreamServer) Recv() (*StreamRequestData, error) {m := new(StreamRequestData)if err := x.ServerStream.RecvMsg(m); err != nil {return nil, err}return m, nil
}var _Stream_serviceDesc = grpc.ServiceDesc{ServiceName: "Stream",HandlerType: (*StreamServer)(nil),Methods:     []grpc.MethodDesc{},Streams: []grpc.StreamDesc{{StreamName:    "GetStream",Handler:       _Stream_GetStream_Handler,ServerStreams: true,},{StreamName:    "PutStream",Handler:       _Stream_PutStream_Handler,ClientStreams: true,},{StreamName:    "AllStream",Handler:       _Stream_AllStream_Handler,ServerStreams: true,ClientStreams: true,},},Metadata: "stream.proto",
}

server.go:

package mainimport ("fmt""go-micro-service-architect/cn/ljxwtl/micro/stream/grpc_proto""google.golang.org/grpc""net""sync""time"
)type Server struct {
}func (s *Server) GetStream(stream *grpc_proto.StreamRequestData, response grpc_proto.Stream_GetStreamServer) error {var count = 0for {count++err := response.Send(&grpc_proto.StreamResponseData{Data: fmt.Sprintf("%d", time.Now().Unix()),})time.Sleep(time.Second)if err != nil {return err}if count > 10 {break}}return nil
}
func (s *Server) PutStream(server grpc_proto.Stream_PutStreamServer) error {for {data, err := server.Recv()if err != nil {fmt.Println(err)break}fmt.Println("服务器接收到的数据=>>>>>>", data)}return nil
}
func (s *Server) AllStream(allStream grpc_proto.Stream_AllStreamServer) error {wg := sync.WaitGroup{}wg.Add(2)go func() {defer wg.Done()for {recv, err2 := allStream.Recv()if err2 != nil {panic(err2)}fmt.Println("服务器接收的数据=>>>>>>", recv)}}()go func() {defer wg.Done()for {err2 := allStream.Send(&grpc_proto.StreamResponseData{Data: fmt.Sprintf("服务器发送的消息:%d---bobby", time.Now().Unix()),})time.Sleep(time.Second)if err2 != nil {panic(err2)}}}()wg.Wait()return nil
}func main() {server := grpc.NewServer()listen, err := net.Listen("tcp", "0.0.0.0:8080")if err != nil {return}grpc_proto.RegisterStreamServer(server, &Server{})err = server.Serve(listen)if err != nil {panic(err)}
}

client.go:

package mainimport ("context""fmt""go-micro-service-architect/cn/ljxwtl/micro/stream/grpc_proto""google.golang.org/grpc""google.golang.org/grpc/credentials/insecure""sync""time"
)func main() {conn, err := grpc.Dial("localhost:8080", grpc.WithTransportCredentials(insecure.NewCredentials()))if err != nil {return}client := grpc_proto.NewStreamClient(conn)// 服务器流stream, err := client.GetStream(context.Background(), &grpc_proto.StreamRequestData{Data: "bobby",})if err != nil {panic(err)}for {responseData, err := stream.Recv()if err != nil {fmt.Println(err)break}fmt.Println(responseData)}// 客户端流putStream, err := client.PutStream(context.Background())if err != nil {panic(err)}var count = 0for {count++err := putStream.Send(&grpc_proto.StreamRequestData{Data: "bobby",})if err != nil {fmt.Println(err)break}time.Sleep(time.Second)if count > 10 {break}}//双向流wg := sync.WaitGroup{}wg.Add(2)allStream, err := client.AllStream(context.Background())if err != nil {panic(err)}go func() {defer wg.Done()for {recv, err2 := allStream.Recv()if err2 != nil {panic(err2)}fmt.Println("客户端接收的数据=>>>>>>", recv)}}()go func() {defer wg.Done()for {err2 := allStream.Send(&grpc_proto.StreamRequestData{Data: fmt.Sprintf("客户端发送的消息:%d---bobby", time.Now().Unix()),})time.Sleep(time.Second)if err2 != nil {panic(err2)}}}()wg.Wait()
}

client的输出:

server的输出:

双向流的交互式代码演示:

Server.go:

package mainimport ("fmt""go-micro-service-architect/cn/ljxwtl/micro/stream""google.golang.org/grpc""net""strconv""sync"
)type server struct {
}func (s *server) GetStream(request *stream.StreamRequestData, server stream.Stream_GetStreamServer) error {var index int = 0for {//time.Sleep(time.Second)_ = server.Send(&stream.StreamResponseData{ResData: "hello ===>>>" + strconv.Itoa(index),})index++if index > 10 {break}}return nil
}func (s *server) PutStream(server stream.Stream_PutStreamServer) error {for {requestData, err := server.Recv()if err != nil {fmt.Println("服务端停止接收数据......")break}fmt.Println(requestData.Data)}return nil
}func (s *server) AllStream(server stream.Stream_AllStreamServer) error {wg := sync.WaitGroup{}wg.Add(2)go func() {var message stringfor {fmt.Println("------------")fmt.Scanf("%s", &message)_ = server.Send(&stream.StreamResponseData{ResData: message,})}wg.Done()}()go func() {for {fmt.Println("-----------")responseData, err := server.Recv()if err != nil {continue}fmt.Println("服务端接收到的数据:", responseData.Data)}wg.Done()}()wg.Wait()return nil
}func main() {newServer := grpc.NewServer()stream.RegisterStreamServer(newServer, &server{})listener, err := net.Listen("tcp", ":8888")if err != nil {panic(err)}err = newServer.Serve(listener)if err != nil {panic(err)}
}

AllClient.go:

package mainimport ("context""fmt""go-micro-service-architect/cn/ljxwtl/micro/stream""google.golang.org/grpc""google.golang.org/grpc/credentials/insecure""io""sync"
)func main() {clientConn, err := grpc.Dial("0.0.0.0:8888", grpc.WithTransportCredentials(insecure.NewCredentials()))if err != nil {panic(err)}client := stream.NewStreamClient(clientConn)allStream, _ := client.AllStream(context.Background())var wg = sync.WaitGroup{}wg.Add(2)go func() {var message stringfor {fmt.Println("------------")fmt.Scanf("%s", &message)_ = allStream.Send(&stream.StreamRequestData{Data: message,})}}()go func() {for {responseData, err := allStream.Recv()if err != nil {if err == io.EOF {fmt.Println("-----------")}continue}fmt.Println("客户端接收到的数据:", responseData.ResData)}wg.Done()}()wg.Wait()
}

GRPC的四种数据流以及案例相关推荐

  1. 11服务方式:gRPC的四种服务方式

    今天这篇文章一看标题就比较特别,因为gRPC本身就是分布式微服务常用的一种通信方式,而我们又要探讨gRPC是如何进行通信的,那就是从源码层面来研究下gRPC服务端与客户端之间更为具体的通信方式,作为业 ...

  2. 跨境电商亚马逊无货源铺货ERP软件四种权限功能案例

    跨境电商ERP软件,亚马逊铺货ERP,亚马逊ERP贴牌,亚马逊ERP独立部署,各个等级权限分配! 运营做店 做店个人运营店铺,一般分为几个店铺,一个店铺,三个店铺,十个店铺,店群等等,授权单个端口,可 ...

  3. gRPC四种模式、认证和授权实战演示

    前言 上一篇对gRPC进行简单介绍,并通过示例体验了一下开发过程.接下来说说实际开发常用功能,如:gRPC的四种模式.gRPC集成JWT做认证和授权等. 正文 1. gRPC四种模式服务 以下案例演示 ...

  4. (三)四种流行的RPC框架(Dubbo/Motan/Thrift/Grpc)

    目录 ● Dubbo ● Motan ● Thrift ● Grpc 上述四种流行RPC框架的对比 ● Dubbo 本来阿里2014年就不在维护Dubbo了,直到2017年9月份又恢复了维护,可能一来 ...

  5. Docker Compose搭建consul群集环境(了解Docker Compose及常用命令,Docker四种网络,Doker指定端口)

    文章目录 Docker Compose搭建consul群集环境 认识Docker Compose IConsul Docker Compose容器编排 Dasker Compose配置常用字段 Bos ...

  6. java向MySQL插入当前时间的四种方式和java时间日期格式化的几种方法(案例说明)...

    转载地址:http://www.devba.com/index.php/archives/4581.html java向MySQL插入当前时间的四种方式和java时间日期格式化的几种方法(案例说明); ...

  7. DL之DNN优化技术:DNN优化器的参数优化—更新参数的四种最优化方法(SGD/Momentum/AdaGrad/Adam)的案例理解、图表可视化比较

    DL之DNN优化技术:DNN优化器的参数优化-更新参数的四种最优化方法(SGD/Momentum/AdaGrad/Adam)的案例理解.图表可视化比较 目录 四种最优化方法简介 优化器案例理解 输出结 ...

  8. 可视化篇(四)——— python绘制双y轴、箱线图、概率分布三种图形及案例

    可视化篇(四)--- python绘制双y轴.箱线图.概率分布三种图形及案例 摘要 绘制双y轴图形 绘制箱线图 绘制概率分布图 摘要 本文演示了如何通过python绘制双y轴.箱线图.概率分布三种图形 ...

  9. Bootstrap4+MySQL前后端综合实训-Day01-PM【position定位的四种方式、Flex布局语法教程及案例(概念、容器属性、项目属性)、双飞翼布局复习、Bootstrap4 教程】

    [Bootstrap4前端框架+MySQL数据库]前后端综合实训[10天课程 博客汇总表 详细笔记] 目   录 HTML中的三种元素(块元素.内联元素.内联块元素) position定位的四种方式 ...

最新文章

  1. Emacs 使用YASnippet
  2. linux内核采取,采用动态加载模块的方式Linux内核编译
  3. 第二课计算机ppt,第二课计算机系统.ppt
  4. ad敷铜后还有部分飞线_网友自制LPL赛区AD选手排名图!阿水Lwx荣誉值已超越Uzi_电竞...
  5. 爬取人民日报_【爬虫系列】人民日报半个世纪的资料(文末福利)
  6. 在计算机系统中 外存储器必须通过,大学计算机基础第4章作业.doc
  7. Castle动态代理拦截器可跟踪模型更改和触发规则
  8. Something about WMI
  9. 实现ios常见菜单效果的思路
  10. 除法运算、商、余数与取模
  11. 二级java考什么_计算机二级Java考试考什么内容?
  12. flex builder 破解
  13. 计算机组成原理习题集
  14. java 正则表达式match_详解正则表达式匹配方法 match()
  15. 使用Hex view编写脚本生成特定格式刷写文件
  16. 硬盘 SMART 检测参数详解[转]
  17. GitHub简介、fork、pull和clone、快速起步
  18. After trying to increase PLL frequency, system shows the error: “Device may be operating in low-powe
  19. Could not open Hibernate Session for transaction; nested exception is org.hibernate.exception.Gener
  20. MySQl 实现 FULL JOIN

热门文章

  1. html5调用手电筒,HTML5的模拟手电筒照明效果
  2. CNC+CRC/SoftPLC/OpenCASCADE/CAD/CAM开源项目收藏
  3. ant design vue全局引用一直提示没有isMoment参数的问题
  4. 扫描识别行驶证的软件技术
  5. 仪器仪表制造业采购数字化方案:集中采购系统为供采双方打造更高效运转平台
  6. Keras的Model模型使用
  7. 于是,我整个人都斯巴达了
  8. Python正则表达式(菜鸡版)
  9. 如何使用微信公众号做营销
  10. SQL Server之STUFF 使用