GO语言工程实践课后作业:实现思路、代码以及路径记录 | 青训营

48 阅读7分钟
  1. 语言进阶

1) 并发 VS 并行

并发是不同的代码块交替执行,也就是交替可以做不同的事情。 并行是不同的代码块同时执行,也就是同时可以做不同的事情。 并发比如多线程程序在一个核的CPU上运行 并行比如多线程程序在多个核的CPU上运行;

goroutine

线程(Threa) :有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。 线程拥有自己独立的栈和共享的堆,共享堆,不共享栈,线程的切换一般也由操作系统调度。

协程(coroutine):又称微线程与子例程(或者称为函数)一样,协程(coroutine)也是一种程序组件。相对子例程而言,协程更为一般和灵活,但在实践中使用没有子例程那样广泛。 和线程类似,共享堆,不共享栈,协程的切换一般由程序员在代码中显式控制。它避免了上下文切换的额外耗费,兼顾了多线程的优点,简化了高并发程序的复杂。 Goroutine和其他语言的协程(coroutine)在使用方式上类似,但从字面意义上来看不同(一个是Goroutine,一个是coroutine),再就是协程是一种协作任务控制机制,在最简单的意义上,协程不是并发的,而Goroutine支持并发的。因此Goroutine可以理解为一种Go语言的协程。同时它可以运行在一个或多个线程上。

2)CSP (Communicating Sequential Processes) CSP 是 Communicating Sequential Process 的简称,中文可以叫做通信顺序进程,是一种并发编程模型,是一个很强大的并发数据模型,是上个世纪七十年代提出的,用于描述两个独立的并发实体通过共享的通讯 channel(管道)进行通信的并发模型。相对于Actor模型,CSP中channel是第一类对象,它不关注发送消息的实体,而关注与发送消息时使用的channel。

Go语言的CSP模型是由协程Goroutine与通道Channel实现:

Go协程goroutine: 是一种轻量线程,它不是操作系统的线程,而是将一个操作系统线程分段使用,通过调度器实现协作式调度。是一种绿色线程,微线程,它与Coroutine协程也有区别,能够在发现堵塞后启动新的微线程。 通道channel: 类似Unix的Pipe,用于协程之间通讯和同步。协程之间虽然解耦,但是它们和Channel有着耦合。

3)Channel

4)其他还有Sync; 并发安全锁;WaitGroup;

  1. 依赖管理 GoPATH -Go Vendor - Go Module

  2. 测试 回归测试-集成测试-单元测试

  3. 例子

1)例子1

package protoexample

import ( 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 FOO int32

const ( FOO_X FOO = 17 )

// Enum value maps for FOO. var ( FOO_name = map[int32]string{ 17: "X", } FOO_value = map[string]int32{ "X": 17, } )

func (x FOO) Enum() *FOO { p := new(FOO) *p = x return p }

func (x FOO) String() string { return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) }

func (FOO) Descriptor() protoreflect.EnumDescriptor { return file_test_proto_enumTypes[0].Descriptor() }

func (FOO) Type() protoreflect.EnumType { return &file_test_proto_enumTypes[0] }

func (x FOO) Number() protoreflect.EnumNumber { return protoreflect.EnumNumber(x) }

// Deprecated: Do not use. func (x *FOO) UnmarshalJSON(b []byte) error { num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) if err != nil { return err } *x = FOO(num) return nil }

// Deprecated: Use FOO.Descriptor instead. func (FOO) EnumDescriptor() ([]byte, []int) { return file_test_proto_rawDescGZIP(), []int{0} }

type Test struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields

Label         *string             `protobuf:"bytes,1,req,name=label" json:"label,omitempty"`
Type          *int32              `protobuf:"varint,2,opt,name=type,def=77" json:"type,omitempty"`
Reps          []int64             `protobuf:"varint,3,rep,name=reps" json:"reps,omitempty"`
Optionalgroup *Test_OptionalGroup `protobuf:"group,4,opt,name=OptionalGroup,json=optionalgroup" json:"optionalgroup,omitempty"`

}

// Default values for Test fields. const ( Default_Test_Type = int32(77) )

func (x *Test) Reset() { *x = Test{} if protoimpl.UnsafeEnabled { mi := &file_test_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } }

func (x *Test) String() string { return protoimpl.X.MessageStringOf(x) }

func (*Test) ProtoMessage() {}

func (x *Test) ProtoReflect() protoreflect.Message { mi := &file_test_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 Test.ProtoReflect.Descriptor instead. func (*Test) Descriptor() ([]byte, []int) { return file_test_proto_rawDescGZIP(), []int{0} }

func (x *Test) GetLabel() string { if x != nil && x.Label != nil { return *x.Label } return "" }

func (x *Test) GetType() int32 { if x != nil && x.Type != nil { return *x.Type } return Default_Test_Type }

func (x *Test) GetReps() []int64 { if x != nil { return x.Reps } return nil }

func (x *Test) GetOptionalgroup() *Test_OptionalGroup { if x != nil { return x.Optionalgroup } return nil }

type Test_OptionalGroup struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields

RequiredField *string `protobuf:"bytes,5,req,name=RequiredField" json:"RequiredField,omitempty"`

}

func (x *Test_OptionalGroup) Reset() { *x = Test_OptionalGroup{} if protoimpl.UnsafeEnabled { mi := &file_test_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } }

func (x *Test_OptionalGroup) String() string { return protoimpl.X.MessageStringOf(x) }

func (*Test_OptionalGroup) ProtoMessage() {}

func (x *Test_OptionalGroup) ProtoReflect() protoreflect.Message { mi := &file_test_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 Test_OptionalGroup.ProtoReflect.Descriptor instead. func (*Test_OptionalGroup) Descriptor() ([]byte, []int) { return file_test_proto_rawDescGZIP(), []int{0, 0} }

func (x *Test_OptionalGroup) GetRequiredField() string { if x != nil && x.RequiredField != nil { return *x.RequiredField } return "" }

var File_test_proto protoreflect.FileDescriptor

var file_test_proto_rawDesc = []byte{ 0x0a, 0x0a, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0c, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x22, 0xc7, 0x01, 0x0a, 0x04, 0x54, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x02, 0x28, 0x09, 0x52, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x12, 0x16, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x3a, 0x02, 0x37, 0x37, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x65, 0x70, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x03, 0x52, 0x04, 0x72, 0x65, 0x70, 0x73, 0x12, 0x46, 0x0a, 0x0d, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0a, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x2e, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x0d, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x1a, 0x35, 0x0a, 0x0d, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x24, 0x0a, 0x0d, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x05, 0x20, 0x02, 0x28, 0x09, 0x52, 0x0d, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x2a, 0x0c, 0x0a, 0x03, 0x46, 0x4f, 0x4f, 0x12, 0x05, 0x0a, 0x01, 0x58, 0x10, 0x11, }

var ( file_test_proto_rawDescOnce sync.Once file_test_proto_rawDescData = file_test_proto_rawDesc )

func file_test_proto_rawDescGZIP() []byte { file_test_proto_rawDescOnce.Do(func() { file_test_proto_rawDescData = protoimpl.X.CompressGZIP(file_test_proto_rawDescData) }) return file_test_proto_rawDescData }

var file_test_proto_enumTypes = make([]protoimpl.EnumInfo, 1) var file_test_proto_msgTypes = make([]protoimpl.MessageInfo, 2) var file_test_proto_goTypes = []any{ (FOO)(0), // 0: protoexample.FOO (*Test)(nil), // 1: protoexample.Test (*Test_OptionalGroup)(nil), // 2: protoexample.Test.OptionalGroup } var file_test_proto_depIdxs = []int32{ 2, // 0: protoexample.Test.optionalgroup:type_name -> protoexample.Test.OptionalGroup 1, // [1:1] is the sub-list for method output_type 1, // [1:1] is the sub-list for method input_type 1, // [1:1] is the sub-list for extension type_name 1, // [1:1] is the sub-list for extension extendee 0, // [0:1] is the sub-list for field type_name }

func init() { file_test_proto_init() } func file_test_proto_init() { if File_test_proto != nil { return } if !protoimpl.UnsafeEnabled { file_test_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*Test); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } file_test_proto_msgTypes[1].Exporter = func(v any, i int) any { switch v := v.(*Test_OptionalGroup); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_test_proto_rawDesc, NumEnums: 1, NumMessages: 2, NumExtensions: 0, NumServices: 0, }, GoTypes: file_test_proto_goTypes, DependencyIndexes: file_test_proto_depIdxs, EnumInfos: file_test_proto_enumTypes, MessageInfos: file_test_proto_msgTypes, }.Build() File_test_proto = out.File file_test_proto_rawDesc = nil file_test_proto_goTypes = nil file_test_proto_depIdxs = nil }

  1. 例子2

分层结构

分为数据层,逻辑层,视图层。 数据层 数据model,用于外部数据的增删改查; 逻辑层 业务entity,用于处理核心业务逻辑输出; 视图层 视图view, 用于处理核外部的交互逻辑;

0201.png

分层结构有三步:参数校验,数据准备,实体封装;