浅谈Go语言并发机制

yizhihongxing

浅谈Go语言并发机制

Go语言并发简介

并发是指同时执行多个任务的能力。Go语言内置了并发编程的支持,可以非常方便地编写高并发程序。

Go语言的并发模型依赖于go函数和channel这两个基本元素。

Go函数

在Go语言中,我们可以用go关键字来启动一个goroutine(轻量级线程),goroutine的调度由Go语言运行时完成。

以下是一个启动goroutine的简单示例:

package main

import (
    "fmt"
    "time"
)

func main() {
    go func() {
        for i := 1; i <= 5; i++ {
            fmt.Println("goroutine: ", i)
            time.Sleep(time.Second)
        }
    }()
    for i := 1; i <= 5; i++ {
        fmt.Println("main: ", i)
        time.Sleep(time.Second)
    }
}

运行结果如下:

main: 1
goroutine: 1
main: 2
goroutine: 2
main: 3
goroutine: 3
main: 4
goroutine: 4
main: 5
goroutine: 5

这里我们启动了一个匿名函数,使用go关键字创建了一个新的goroutine。在主函数中,我们也打印了5个消息。

可以发现,主函数和goroutine之间并没有严格的交替执行,而是由Go语言运行时随机调度的。

Channel

在Go语言中,我们可以使用channel来进行协程间通信。

channel是Go语言内置的双向链表,支持并发的读写操作。channel类似于Unix中的管道,可以用于协程之间的同步和通信。

以下是一个channel的简单示例:

package main

import (
    "fmt"
)

func main() {
    c := make(chan int)
    go func() {
        for i := 1; i <= 5; i++ {
            c <- i
        }
        close(c)
    }()
    for v := range c {
        fmt.Println(v)
    }
}

运行结果如下:

1
2
3
4
5

这里我们创建了一个大小为1的channel,用于在goroutine和主函数之间通信。在匿名函数中,我们通过c <- i向通道中写入数据,最后通过close(c)关闭通道。在主函数中,我们使用for...range语句从通道中读取数据,并打印输出。

Go语言并发机制

Go语言并发机制通过goroutine和channel来实现,并发模型简单且易于使用,适合处理高并发场景。

以下是一个并发模型的简单示例:

package main

import (
    "fmt"
)

func main() {
    c := make(chan int)
    go func() {
        for i := 1; i <= 5; i++ {
            c <- i
        }
        close(c)
    }()
    for v := range c {
        go func(v int) {
            fmt.Println("goroutine: ", v)
        }(v)
    }
}

运行结果如下:

goroutine:  3
goroutine:  4
goroutine:  5
goroutine:  1
goroutine:  2

这里我们先创建了一个通道,然后在一个goroutine中向通道中写入数据,最后关闭通道。在主函数中,我们使用for...range语句从通道中读取数据,并使用go关键字启动一个新的goroutine打印消息。

从运行结果可以看出,启动的五个goroutine并不是严格按照顺序依次执行,而是由Go语言运行时随机调度的。

另外,由于我们使用了go func(v int){fmt.Println("goroutine: ", v)}(v)的形式来启动goroutine,所以每个goroutine都是在新的线程中执行,相互之间并不会互相影响。而如果不使用go关键字来启动goroutine,则当前的goroutine就会阻塞等待消息被读取,从而无法并发执行其他的任务。

例子说明

goroutine并发下载文件

在多数情况下,我们下载很多小文件的时候,单线程下载速度太慢,很容易使用户等待。使用goroutine则可以简单地达到并发下载的目的。

以下是一个使用goroutine并发下载文件的简单示例:

package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
    "time"
)

func downloadFile(url string, fileName string) {
    resp, err := http.Get(url)
    defer resp.Body.Close()

    if err != nil {
        fmt.Println("Error: ", err)
        return
    }

    body, err := ioutil.ReadAll(resp.Body)

    if err != nil {
        fmt.Println("Error: ", err)
        return
    }

    err = ioutil.WriteFile(fileName, body, 0644)

    if err != nil {
        fmt.Println("Error: ", err)
        return
    }

    fmt.Println("Downloaded: ", url)
}

func main() {
    c := make(chan int)
    files := []string{
        "https://golang.google.cn/doc/gopher/bumper.png",
        "https://golang.google.cn/pkg/http/",
        "https://golang.google.cn/pkg/io/",
    }
    for _, url := range files {
        go func(url string) {
            fileName := url[strings.LastIndex(url, "/")+1:]
            downloadFile(url, fileName)
            c <- 1
        }(url)
    }
    for i := 0; i < len(files); i++ {
        <-c
    }
}

运行结果如下:

Downloaded:  https://golang.google.cn/pkg/io/
Downloaded:  https://golang.google.cn/doc/gopher/bumper.png
Downloaded:  https://golang.google.cn/pkg/http/

这里我们定义了downloadFile函数用于下载文件,然后在主函数中使用for循环启动多个goroutine并发执行下载任务。我们使用通道来同步各个goroutine执行的任务。

从运行结果中可以看出,这个程序可以同时下载多个文件并且可以很快地完成所有任务。

超时请求

在网络请求中,经常需要设置超时时间,以防止请求长时间未响应而阻塞应用程序。使用goroutine可以方便地实现超时请求的功能。

以下是一个使用goroutine实现超时请求的简单示例:

package main

import (
    "fmt"
    "net/http"
    "time"
)

func main() {
    c := make(chan error)
    url := "https://golang.google.cn/pkg/io/"
    go func() {
        resp, err := http.Get(url)
        if err != nil {
            c <- err
        } else {
            defer resp.Body.Close()
            c <- nil
        }
    }()
    select {
    case err := <-c:
        if err != nil {
            fmt.Println("Error: ", err)
        } else {
            fmt.Println("Request OK")
        }
    case <-time.After(3 * time.Second):
        fmt.Println("Request timed out")
    }
}

运行结果如下:

Request OK

这里我们创建了一个通道和一个goroutine,同时使用了selecttime.After函数来模拟超时。当请求超时或者执行完成后,程序可以自动终止。如果在规定时间内请求没有得到响应,则打印提示信息。

结论

Go语言的并发机制基于goroutine和channel实现,简单易用,适合处理高并发场景。在实际应用中,我们可以通过使用goroutine来实现并发执行任务,使用channel来进行不同goroutine之间的协作和通信,从而实现高效的并发编程。

如果我们在合适的场景下使用goroutine和channel,可以显著地提高程序的性能和吞吐量,从而更好地满足实际需求。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:浅谈Go语言并发机制 - Python技术站

(0)
上一篇 2023年5月17日
下一篇 2023年5月17日

相关文章

  • linux下c语言的多线程编程

    关于Linux下C语言的多线程编程,可以看做是单CPU多任务或并发执行的模式,使用线程可以有效地提高应用程序的执行效率和利用率,对于高并发场景下的服务端应用尤为重要。下面是具体的攻略: 一、线程的创建和销毁 Linux下的多线程编程主要用到pthread库,使用pthread库需要包含< pthread.h >头文件。 可以使用pthread_c…

    多线程 2023年5月17日
    00
  • Java线程并发中常见的锁机制详细介绍

    Java线程并发中常见的锁机制详细介绍 在Java的多线程并发编程中,锁机制是非常重要的,因为有效地使用锁机制可以确保线程的安全性和数据的一致性。下面将详细讲解Java线程并发中常见的锁机制以及它们的优缺点和适用场景。 synchronized关键字 synchronized是Java中最基本和最常用的锁机制,用于控制线程对共享资源的访问。synchroni…

    多线程 2023年5月16日
    00
  • 详解JUC并发编程中的进程与线程学习

    详解JUC并发编程中的进程与线程学习攻略 一、进程与线程的概念及区别 进程:是指正在执行的程序的实例。每个进程都有独立的内存空间,它可以包括多个线程。 线程:是指程序中独立、并发执行的最小单位,它直接依赖于进程,一个进程可以创建多个线程。 进程与线程的最大区别在于进程是资源分配的最小单位,线程是CPU调度的最小单位。线程共享进程的内存空间以及其他系统资源。 …

    多线程 2023年5月16日
    00
  • Java多线程与线程池技术分享

    Java多线程与线程池技术分享 1. 多线程 什么是线程? 线程是一个程序执行流的最小单元,一个程序至少有一个执行流,即主线程。主线程在JVM启动时就存在了。 创建线程的方式 继承Thread类 重写Thread类的run()方法。 public class MyThread extends Thread { @Override public void ru…

    多线程 2023年5月17日
    00
  • GO中sync包自由控制并发示例详解

    在Go语言中,sync包提供了许多同步原语和锁,可以在并发编程中实现不同的控制并发的方式。下面是关于如何自由控制并发的示例详解。 使用WaitGroup控制并发执行 使用sync包的WaitGroup类型,可以实现并发执行多个任务,并等待所有任务完成后再执行后续操作的功能。WaitGroup内部有一个计数器,每增加一个goroutine,计数器加1,每个go…

    多线程 2023年5月17日
    00
  • 分析python并发网络通信模型

    下面我结合示例详细讲解“分析python并发网络通信模型”的完整攻略。 一、了解Python的GIL Python语言自身带有GIL(全局解释器锁)。GIL是一种互斥锁,它保证同时只有一个线程在解释器中被执行,这样也就导致了Python的多线程程序并不能利用多核CPU的优势。 因此,在Python中实现并发多线程需要使用多个进程而不是多个线程,或者使用一些协…

    多线程 2023年5月17日
    00
  • 详解在SpringBoot如何优雅的使用多线程

    下面我将详细讲解在SpringBoot如何优雅地使用多线程。 为什么需要使用多线程 在程序中使用多线程可以充分发挥多核处理器的性能,提升程序执行效率。而在SpringBoot中使用多线程,可以进一步提升Web应用的性能和响应速度。 多线程的应用场景 应用场景通常包括: 并发请求:同时处理多个请求 异步调用:在一个方法中异步执行耗时的操作,从而减少阻塞等待的时…

    多线程 2023年5月17日
    00
  • C#多线程系列之多线程锁lock和Monitor

    C#多线程系列之多线程锁lock和Monitor 在多线程编程中,为了保证数据的安全性和正确性,需要使用到锁。本文主要介绍C#中的多线程锁lock和Monitor。 什么是锁? 锁是一种同步机制,可以确保多个线程在访问共享资源时不会产生冲突。在执行某个代码块时,只有获得了锁的线程才能执行,其他线程则需要等待锁的释放。这样可以保证同一时刻只有一个线程对共享资源…

    多线程 2023年5月16日
    00
合作推广
合作推广
分享本页
返回顶部