Go语言任务调度

Goroutine简介定义:Goroutine是一种轻量级线程,由Go运行时管理。它比操作系统级别的线程更轻量,创建成本低,切换速度快。创建方式:通过go关键字启动一个新goroutine。gofunc(){fmt.Println("Hellofromgoroutine"

Goroutine简介

  • 定义:Goroutine是一种轻量级线程,由Go运行时管理。它比操作系统级别的线程更轻量,创建成本低,切换速度快。
  • 创建方式:通过go关键字启动一个新goroutine。
go func() {
    fmt.Println("Hello from goroutine")
}()

Channel的作用

  • 定义:Channel是goroutine之间通信的管道,用于发送和接收数据。
  • 声明与使用
ch := make(chan int) // 声明一个整型channel
ch <- 42             // 向channel发送数据
x := <-ch            // 从channel接收数据
fmt.Println(x)       // 输出: 42

同步与异步

  • 同步:等待一个操作完成后再执行下一步。
  • 异步:不等待操作完成,直接执行下一步。

并发模式

生产者消费者模型:通过channel连接生产者和消费者。

func producer(ch chan<- int) {
    for i := 0; i < 10; i++ {
        ch <- i
    }
    close(ch)
}

func consumer(ch <-chan int) {
    for n := range ch {
        fmt.Println(n)
    }
}

func main() {
    ch := make(chan int)
    go producer(ch)
    consumer(ch)
}

工作池:通过固定数量的goroutine处理任务队列。

type WorkerPool struct {
    jobs  chan int
    done  chan bool
    count int
}

func NewWorkerPool(n int) *WorkerPool {
    return &WorkerPool{
        jobs:  make(chan int, 100),
        done:  make(chan bool, n),
        count: n,
    }
}

func (p *WorkerPool) Start() {
    for i := 0; i < p.count; i++ {
        go func() {
            for job := range p.jobs {
                fmt.Println("Working on", job)
                time.Sleep(time.Second)
            }
            p.done <- true
        }()
    }
}

func (p *WorkerPool) AddJob(jobs ...int) {
    for _, job := range jobs {
        p.jobs <- job
    }
}

func (p *WorkerPool) Wait() {
    for i := 0; i < p.count; i++ {
        <-p.done
    }
    close(p.jobs)
}

func main() {
    wp := NewWorkerPool(5)
    wp.Start()
    wp.AddJob(1, 2, 3, 4, 5)
    wp.Wait()
}

超时控制

使用context包可以方便地设置超时。

ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
defer cancel()

select {
case <-ctx.Done():
    fmt.Println("Timed out")
case result := <-ch:
    fmt.Println("Result:", result)
}

错误处理

在并发程序中,错误处理尤为重要。

func doWork(ch chan<- error) {
    defer func() {
        if r := recover(); r != nil {
            ch <- errors.New("panic occurred")
        }
    }()

    // 可能引发panic的操作
    fmt.Println(1 / 0)
}

func main() {
    ch := make(chan error)
    go doWork(ch)
    if err := <-ch; err != nil {
        log.Fatal(err)
    }
}

性能考量

  • Goroutine的数量不宜过多,否则会导致上下文切换频繁,影响性能。
  • Channel的缓冲区大小需合理设置,过大会占用内存,过小则可能造成goroutine阻塞。

实战案例

假设我们需要开发一个简单的Web服务器,该服务器能够同时处理多个客户端请求,并且每个请求都可能触发一些耗时较长的操作(如数据库查询)。我们可以利用goroutine和channel来实现这一功能:


package main

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

func handleRequest(w http.ResponseWriter, r *http.Request) {
    // 模拟耗时操作
    ch := make(chan string)
    go func() {
        time.Sleep(2 * time.Second)
        ch <- "Hello, World!"
    }()

    // 等待结果返回
    result := <-ch
    fmt.Fprintln(w, result)
}

func main() {
    http.HandleFunc("/", handleRequest)
    log.Fatal(http.ListenAndServe(":8080", nil))...

剩余50%的内容订阅专栏后可查看

点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论