Golang进阶

"白昼会边长,照亮心脏,让万物生长。"

一、Golang进阶

我们对golang的语法进行了一定的了解后,也算是入门了。本节的进阶篇围绕三个方向展开,Goroutine 、 Channel 、Sync。

如何理解并行与并发?

并行是指“并排行走”或“同时实行或实施”。
在操作系统中是指,一组程序按独立异步的速度执行,无论从微观还是宏观,程序都是一起执行的。对比地,并发是指:在同一个时间段内,两个或多个程序执行,有时间上的重叠(宏观上是同时,微观上仍是顺序执行)

并发,在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行,但任一个时刻点上只有一个程序在处理机上运行。

下面两张图就可以区别并发与并行;

并发:

并行:

同样,随着技术的迭代升级也有了并行+并发:

看完上面的图解。
并发的实质是针对单核CPU,它的交替调度不同任务的能力
并行的是追是针对多核CPU,它指的是多个核心同时执行多个任务的能力。
由此,单核 CPU 只能并发,无法并行。并行,只存在于多核CPU的硬件条件下。
而在多核CPU中,并发并行都会同时存在,这是提高CPU处理任务能力的重要手段

(1)Goroutine

协程,又叫做轻量级线程。这在Golang这样的编程语言中特别流行。

Go协程的特点:
1.独立的栈空间
2.共享堆空间
3. 协程调度由用户控制(进程的控制是有操作系统控制,程序员不能控制)

不管是父进程创建的子进程,还是在linuxPOSIX提供的线程库。其中的管理都是交由操作系统。因此,在程序执行的过程中,总会存在执行状态的切换(用户到内核,内核到用户)。但是,golang中的协程完完全全解决了这个问题。

协程:用户态,轻量级线程。
线程:内核态,线程可以跑多个协程。
创建一个线程栈大概需要 1MB 左右,而协程栈大概只需要几 KB或者几十KB。
package main

import (
    "fmt"
    "time"
)

func hello(i int) {
    fmt.Println("go() to hello", i)
}

func HelloRotinue() {
    for i := 0; i < 5; i++ {
        go hello(i)
    }
    time.Sleep(time.Second)
}

func main() {
    HelloRotinue()
    for i := 0; i < 5; i++ {
        fmt.Println("main() to hello", i)
        time.Sleep(time.Second)
    }
}

我们在调用打印hello的函数前面加上关键字"go"。表面,我们起一个协程来调用这个函数。

但我们此时没有设置HelloRotinue为线程,因此是等待该函数调用完时,才开始进行主线程main。

此时,只需要在该函数前加上go,这两个执行流就不会处在所谓的"阻塞"状态,而是各管各的。

什么是CSP?

CSP理念: 以通信的方式来共享内存。Go 的并发哲学,依赖于 CSP 模型。

大多数编程语言,在如何实现并发的问题上,采用的都是基于线程和内存同步访问控制。而Go 的并发编程的模型则用 goroutine 和 channel 来替代。

Goroutine 和线程类似,channel 和 mutex (用于内存同步访问控制的互斥锁)类似。

我们在linux处着重讲了,实现进程间的本质,就是让每个进程(线程)可看到同一份公共资源。而这个而资源,也叫做临界区。

通过共享内存实现通信;

通过通信共享内存;

(2)Channel

make(chan+元素类型,[缓冲大小])
例如:
无缓冲通道 make(chan int)
有缓冲通道 make(chan int,2)

比如,现在我们要执行完成一个任务。协程1发送0~9数字,协程2拿到数字后计算它们的平方,并发送给主线程,并在主线程处打印。

最后我们也可以得到结果。

(3)Sync

sync(意指Synchronize,即“同步”)为UNIX操作系统的标准系统调用,功能为将内核文件系统缓冲区的所有数据。

sync:
Package sync provides basic synchronization primitives such as mutual exclusion locks. Other than the Once and WaitGroup types, most are intended for use by low-level library routines. Higher-level synchronization is better done via channels and communication.

包同步提供了基本的同步原语,如互斥锁。除了Once和WaitGroup类型之外,大多数类型都是供低级库例程使用的。更高级别的同步最好通过信道和通信来完成。

并发安全 Lock

我们期待五个协程对x进行2000循环地自增加1

package main

import (
    "fmt"
    "sync"
    "time"
)

var (
    x    int64
    lock sync.Mutex
)

func addWithLock() {
    for i := 0; i < 2000; i++ {
        lock.Lock()
        x += 1
        lock.Unlock()
    }
}

func addWithOutLock() {
    for i := 0; i < 2000; i++ {
        x += 1
    }
}

func main() {
    x = 0
    for i := 0; i < 5; i++ {
        go addWithOutLock()
    }
    fmt.Println("WithOutLock: ", x)
    time.Sleep(time.Second)

    x = 0
    for i := 0; i < 5; i++ {
        go addWithLock()
    }
    time.Sleep(time.Second)
    fmt.Println("WithLock: ", x)
}

WaitGroup

这个类里有三个比较重要的函数;

我们简简单单地用五个协程分别打印。

我们对代码进行一定的改进。让打印后的结果进行阻塞。

总结:

以上就是golang面向并发编程的相关介绍。本篇涉及的三个方面,协程(Gorotinue),信道(Channel)通过通信实现共享内存,sync关键字,支持同步互斥的并发安全操作。

本篇也就到此结束了~感谢你的阅读

祝你好运,向阳而生

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
很高兴回答你关于Golang语法进阶的问题!Golang是一门简洁高效的编程语言,下面我将分享一些Golang语法的进阶知识。 1. 嵌套结构体:在Golang中,你可以在一个结构体中嵌套另一个结构体。这样可以更好地组织和管理代码。例如: ```go type Person struct { Name string Age int } type Employee struct { Person Salary int } ``` 这里的Employee结构体嵌套了Person结构体,可以通过Employee结构体访问Person结构体的字段。 2. 接口和类型断言:Golang中的接口是一种约定,定义了一组方法。通过接口,你可以实现多态性。类型断言则用于检查接口变量是否实现了某个接口。例如: ```go type Shape interface { Area() float64 } type Circle struct { Radius float64 } func (c Circle) Area() float64 { return math.Pi * c.Radius * c.Radius } func main() { var shape Shape = Circle{Radius: 5} if circle, ok := shape.(Circle); ok { fmt.Println("Area of circle:", circle.Area()) } } ``` 3. 并发编程:Golang内置了并发编程的支持,通过goroutine和通道(channel)可以实现轻量级线程间通信。例如: ```go func worker(id int, jobs <-chan int, results chan<- int) { for j := range jobs { fmt.Println("Worker", id, "processing job", j) time.Sleep(time.Second) // 模拟耗时操作 results <- j * 2 } } func main() { jobs := make(chan int, 5) results := make(chan int, 5) // 启动三个goroutine for w := 1; w <= 3; w++ { go worker(w, jobs, results) } // 发送5个任务 for j := 1; j <= 5; j++ { jobs <- j } close(jobs) // 输出结果 for r := 1; r <= 5; r++ { fmt.Println(<-results) } } ``` 以上是Golang语法进阶的一些例子,希望对你有帮助!如果你有更多问题,欢迎继续提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值