欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

1. Hello Go(Go Tutorial)

程序员文章站 2022-03-15 22:25:17
...

Hello Go(Go Tutorial)

1. 关于 Go 语言的介绍

1.1 用 Go 解决现代编程难题

当今的软件开发,开发人员不得不在快速开发和性能之间做出抉择。C 和 C++ 类的语言提供了很快的执行速度,而 Ruby 和 Python 则更擅长于快速开发。Go 语言在这两者之间架起了桥梁,不仅提供了高性能的语言,同时也让开发更快速。

具体体现在以下几个小节中。

1.1.1 开发速度

编译一个大型的 C 或 C++ 项目所花费的时间往往很长,而 Go 语言使用了更加智能的编译器,并简化了解决依赖的算法,最终提供了更快的编译速度。(编译 Go 程序时,编译器只会关注那些直接引用的库,而不是像 Java、C 和 C++ 那样,要遍历依赖链中所有依赖的库)

因为没有从编译代码到执行代码的中间过程,用动态语言编写的应用程序可以快速的看到输出。但这方面的代价是,动态语言并不提供静态语言的类型安全检查,无法避免在运行时出现的类型错误。而 Go 语言的编译器能够帮用户捕获这个类型错误。

1.1.2 并发

现代计算机都拥有多个核,但是大部分编程语言都没有有效的工具让程序可以轻易的利用这些资源,这些语言需要写大量的线程同步代码来利用多个核,很容易导致错误。

Go 语言对并发的支持是这门语言最重要的特性之一。

  • goroutine 很像线程,但它占用的内存远少于线程,使用它需要的代码更少。
  • 通道(channel)是一种内置的数据结构,可以让用户在不同的 goroutine 之间同步发送具有类型的消息。这种编程模型更倾向于在 goroutine 之间发送消息,而不是让多个 goroutine 争夺同一数据的使用权。

1. goroutine

goroutine 是可以与其他 goroutine 并发执行的函数,同时也会与主程序并行执行。在其他语言中,你需要使用线程来完成同样的事情,而在 Go 语言中会使用同一个线程来执行多个 goroutine。

goroutine 使用的内存比线程更少,Go 语言在运行时会自动在配置的一组逻辑处理器上调度执行 goroutine,每个逻辑处理器绑定到一个操作系统的线程上,这让用户的应用程序执行效率更高,而并发工作量显著减少。

package main

import (
    "fmt"
    "runtime"
    "log"
    "os"
    "sync"
)

var wg sync.WaitGroup

func writeLog(msg string) {
    defer wg.Done()

    fileName := "test.log"
    logFile, err := os.Create(fileName)
    defer logFile.Close()
    if err != nil {
        log.Fatalln("open file error")
    }
    debugLog := log.New(logFile, "[Debug]", log.LstdFlags)
    debugLog.Printf("a debug message: %s", msg)

    debugLog.SetPrefix("[Info]")
    debugLog.Printf("a info message: %s", msg)

    debugLog.SetFlags(debugLog.Flags() | log.LstdFlags)
    debugLog.Printf("a different prefix: %s", msg)
}

func main()  {
    runtime.GOMAXPROCS(1)
    wg.Add(1)

    fmt.Println("Start")
    go writeLog("this is test")
    fmt.Println("waiting goroutine finish")
    wg.Wait()
    fmt.Println("End")
}

2 通道

通道是一种数据结构,可以让 goroutine 之间进行安全的数据通信。通道可以帮用户避免其他语言里常见的共享内存访问的问题。

并发的难点就在于要确保其他并发运行的进程、线程或 goroutine 不会意外修改用户的数据。当不同的线程在没有同步保护的情况下修改同一个数据时,总会发生灾难。在其他语言中,如果使用全局变量或这共享内存,必须使用复杂的锁规则来防止对同一变量的不同步修改。

1.1.3 Go 语言的类型系统

Go 语言提供了灵活的、无继承的类型系统,无需降低运行性能就能最大程度上复用代码。

这个类型系统依旧支持面向对象开发,但避免了传统面向对象的问题(需要考虑抽象类和接口的设计)。Go 开发者使用组合涉及模式,只需要简单地将一个类型嵌入另一个类型中,就能复用所有所有的功能。

1. 类型简单

Go 语言不仅有类似 intstring 这样的内置类型,还支持用户定义的类型。

2. Go 接口对一组行为建模

接口用于描述类型的行为。

在 Go 语言中,只需要实现接口的所有方法,那么这个类型的实例就是接口类型的实例,不需要额外的声明。而在 Java 这种严格的面向对象的语言中,类必须实现接口中所有的方法并且需要显示的声明接口,才能成为这个接口的实例。

Go 语言接口更小,只倾向与定义一个单一的动作,这样有利于使用组合来复用代码。

1.1.4 内存管理

不当的内存管理会导致程序崩溃或内存泄漏,甚至让整个操作系统崩溃。Go 语言拥有现代化的垃圾回收机制,能帮你解决这个问题。

在 C 和 C++ 中,使用内存要先分配内存,使用完毕后需要将其释放,尤其在并发模式下,追踪内存的使用情况变得尤为困难。而 Go 语言把内存管理交给专业的编译器去做,而让程序员专注于更有趣的事情。

1.2 你好,Go

/** main 包会被编译成可执行文件
  * 如果 main 函数不在 main 包中,编译器就不会生成可执行文件
  */
package main

// 导入包
import "fmt"

// init 函数在 main 函数之前被调用
func init() {
    fmt.Println("func init run before main")
}

// 程序的主入口
func main()  {
    fmt.Println("Hello, Golang")
}