Go语言复习-002

61 阅读3分钟

什么是 Goroutine?

Goroutine 是 Go 语言中的一种轻量级线程,可以在单个进程中同时执行多个任务。Goroutine 具有高效、可扩展、协作式调度等特点,是 Go 语言并发编程的核心。

示例代码:

package main

import (
	"fmt"
	"time"
)

func main() {
	go func() {
		time.Sleep(1 * time.Second)
		fmt.Println("Hello, world!")
	}()
	fmt.Println("Goroutine started")
	time.Sleep(2 * time.Second)
}

如何避免 Goroutine 泄漏?

避免 Goroutine 泄漏的方法包括:确保 Goroutine 及时退出,避免创建过多的 Goroutine,使用带有缓冲区的 Channel,使用 context 包中的 Context,以及使用 sync 包中的 WaitGroup 等。

示例代码:

package main

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

func main() {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	var wg sync.WaitGroup
	wg.Add(1)

	go func() {
		defer wg.Done()
		for {
			select {
			case <-ctx.Done():
				fmt.Println("Goroutine stopped")
				return
			default:
				fmt.Println("Hello, world!")
				time.Sleep(1 * time.Second)
			}
		}
	}()

	time.Sleep(5 * time.Second)
	cancel()
	wg.Wait()
}

什么是 Channel?有哪些使用场景?

Channel 是用于 Goroutine 之间通信的一种同步原语,可以用来传递数据和控制流。Channel 的使用场景包括:Goroutine 之间进行数据传递、Goroutine 之间进行同步、实现线程池、实现生产者-消费者模型等。

示例代码:

package main

import (
	"fmt"
	"time"
)

func main() {
	ch := make(chan int)

	go func() {
		for i := 0; i < 10; i++ {
			ch <- i
			time.Sleep(500 * time.Millisecond)
		}
		close(ch)
	}()

	for {
		val, ok := <-ch
		if !ok {
			fmt.Println("Channel closed")
			break
		}
		fmt.Println(val)
	}

	fmt.Println("Done")
}

什么是 WaitGroup?如何使用它?

WaitGroup 是用于等待一组 Goroutine 完成任务的一种同步原语。使用 WaitGroup 可以避免主 Goroutine 提前退出,等待所有 Goroutine 完成后再退出。

示例代码:

package main

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

func main() {
	var wg sync.WaitGroup
	wg.Add(2)

	go func() {
		defer wg.Done()
		time.Sleep(1 * time.Second)
		fmt.Println("Goroutine 1 completed")
	}()

	go func() {
		defer wg.Done()
		time.Sleep(2 * time.Second)
		fmt.Println("Goroutine 2 completed")
	}()

	wg.Wait()
	fmt.Println("All Goroutines completed")
}

Go中的锁机制是什么?

Go 中的锁机制包括 Mutex、RWMutex、sync.WaitGroup、sync.Once 等。这些锁机制可以用于并发控制和同步,保证 Goroutine 的正确性和数据的一致性。

什么是 Mutex?与 RWMutex 有什么区别?

Mutex 是 Go 中的一种互斥锁,用于保护共享资源的访问。与 RWMutex 不同,Mutex 是一种排他锁,只能被一个 Goroutine 占用,其他 Goroutine 需要等待。RWMutex 是一种读写锁,允许多个 Goroutine 同时读取共享资源,但只允许一个 Goroutine 写入共享资源。

示例代码:

package main

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

func main() {
	var mu sync.Mutex
	var rwmu sync.RWMutex
	var wg sync.WaitGroup

	wg.Add(2)

	go func() {
		defer wg.Done()
		mu.Lock()
		defer mu.Unlock()
		fmt.Println("Mutex acquired")
		time.Sleep(1 * time.Second)
	}()

	go func() {
		defer wg.Done()
		rwmu.RLock()
		defer rwmu.RUnlock()
		fmt.Println("RWMutex read lock acquired")
		time.Sleep(1 * time.Second)
	}()

	wg.Wait()
}

如何避免死锁?

避免死锁的方法包括:避免嵌套锁、避免锁的循环依赖、使用带缓冲的 Channel、使用 timeout 和 context 控制 Goroutine 的执行等。

示例代码:

package main

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

func main() {
	var mu1 sync.Mutex
	var mu2 sync.Mutex

	var wg sync.WaitGroup
	wg.Add(2)

	go func() {
		defer wg.Done()
		mu1.Lock()
		defer mu1.Unlock()
		fmt.Println("Mutex 1 acquired")
		time.Sleep(1 * time.Second)
		mu2.Lock()
		defer mu2.Unlock()
		fmt.Println("Mutex 2 acquired")
	}()

	go func() {
		defer wg.Done()
		mu2.Lock()
		defer mu2.Unlock()
		fmt.Println("Mutex 2 acquired")
		time.Sleep(1 * time.Second)
		mu1.Lock()
		defer mu1.Unlock()
		fmt.Println("Mutex 1 acquired")
	}()

	wg.Wait()
}

什么是 defer 关键字?使用它的好处是什么?

defer 是 Go 中的一种延迟执行机制,可以在函数返回前执行一些清理或收尾工作。defer 的好处包括:代码简洁、易于维护、避免资源泄漏等。

示例代码:

package main

import (
	"fmt"
	"os"
)

func main() {
	f, err := os.Open("file.txt")
	if err != nil {
		panic(err)
	}
	defer f.Close()

	data := make([]byte, 1024)
	if _, err := f.Read(data); err != nil {
		panic(err)
	}

	fmt.Println(string(data))
}

什么是 panic 和 recover?

panic 和 recover 是用于处理程序异常情况的机制。当程序发生错误时,可以使用 panic 抛出一个异常,然后使用 recover 恢复程序执行。panic 和 recover 应该谨慎使用,避免滥用。

示例代码:

package main

import "fmt"

func main() {
	defer func() {
		if err := recover(); err != nil {
			fmt.Println("Recovered from panic:", err)
		}
	}()

	panic("Something went wrong")
}