golang并发官方示例

文章目录

  • Goroutines
  • Channels
  • Buffered Channels
  • Range and Close
  • Select
  • fatal error: all goroutines are asleep - deadlock!
  • Default Selection
  • sync.Mutex
  • Exercise: Web Crawler

官方网站

Goroutines

A goroutine is a lightweight thread managed by the Go runtime.

go f(x, y, z)
starts a new goroutine running

f(x, y, z)
The evaluation of f, x, y, and z happens in the current goroutine and the execution of f happens in the new goroutine.

Goroutines run in the same address space, so access to shared memory must be synchronized. The sync package provides useful primitives, although you won’t need them much in Go as there are other primitives. (See the next slide.)

package mainimport ("fmt""time"
)func say(s string) {for i := 0; i < 5; i++ {time.Sleep(100 * time.Millisecond)fmt.Println(s)}
}func main() {go say("world")say("hello")
}

Channels

Channels are a typed conduit(管道) through which you can send and receive values with the channel operator, <-.

ch <- v // Send v to channel ch.
v := <-ch // Receive from ch, and
// assign value to v.
(The data flows in the direction of the arrow.)

Like maps and slices, channels must be created before use:

ch := make(chan int)
By default, sends and receives block until the other side is ready. This allows goroutines to synchronize without explicit locks or condition variables.

The example code sums the numbers in a slice, distributing the work between two goroutines. Once both goroutines have completed their computation, it calculates the final result.

package mainimport "fmt"func sum(s []int, c chan int) {sum := 0for _, v := range s {sum += v}c <- sum // send sum to c
}func main() {s := []int{7, 2, 8, -9, 4, 0}c := make(chan int)go sum(s[:len(s)/2], c)go sum(s[len(s)/2:], c)x, y := <-c, <-c // receive from cfmt.Println(x, y, x+y)
}

Buffered Channels

Channels can be buffered. Provide the buffer length as the second argument to make to initialize a buffered channel:

ch := make(chan int, 100)
Sends to a buffered channel block only when the buffer is full. Receives block when the buffer is empty.

Modify the example to overfill the buffer and see what happens.

package mainimport "fmt"func main() {ch := make(chan int, 2)ch <- 1ch <- 2fmt.Println(<-ch)fmt.Println(<-ch)
}

Range and Close

A sender can close a channel to indicate that no more values will be sent. Receivers can test whether a channel has been closed by assigning a second parameter to the receive expression: after

v, ok := <-ch
ok is false if there are no more values to receive and the channel is closed.

The loop for i := range c receives values from the channel repeatedly until it is closed.

Note: Only the sender should close a channel, never the receiver. Sending on a closed channel will cause a panic.

Another note: Channels aren’t like files; you don’t usually need to close them. Closing is only necessary when the receiver must be told there are no more values coming, such as to terminate a range loop.

package mainimport ("fmt"
)func fibonacci(n int, c chan int) {x, y := 0, 1for i := 0; i < n; i++ {c <- xx, y = y, x+y}close(c)
}func main() {c := make(chan int, 10)go fibonacci(cap(c), c)for i := range c {fmt.Println(i)}
}

Select

The select statement lets a goroutine wait on multiple communication operations.

A select blocks until one of its cases can run, then it executes that case. It chooses one at random if multiple are ready.

package mainimport "fmt"func fibonacci(c, quit chan int) {x, y := 0, 1for {select {case c <- x:x, y = y, x+ycase <-quit:fmt.Println("quit")return}}
}func main() {c := make(chan int)quit := make(chan int)go func() {for i := 0; i < 10; i++ {fmt.Println(<-c)}quit <- 0}()fibonacci(c, quit)
}

fatal error: all goroutines are asleep - deadlock!

[kou@python 2lessson]$ !g
go run select.go 
0
1
1
2
3
5
8
13
21
34
quitpackage mainimport "fmt"func fibonacci(c, quit chan int) {x, y := 0, 1for {select {case c <- x:x, y = y, x+ycase <-quit:fmt.Println("quit")return}}
}func main() {c := make(chan int)quit := make(chan int)// go func() {for i := 0; i < 10; i++ {fmt.Println(<-c)}quit <- 0// }()fibonacci(c, quit)
}

注释掉go func()来理解go func的功能。
fatal error: all goroutines are asleep - deadlock!
死锁:首先我们这里通过make(chan int),开辟的通道是一种无缓冲通道,当对这个缓冲通道写的时候,会一直阻塞等到某个协程对这个缓冲通道读
main函数的执行在go语言中就是一个协程,所以在执行到fmt.Println(<-c),执行main函数的协程将被阻塞,换句话说main函数被阻塞了,后面的就执行不到了!

Default Selection

The default case in a select is run if no other case is ready.

Use a default case to try a send or receive without blocking:

select {
case i := <-c:
// use i
default:
// receiving from c would block
}

package mainimport ("fmt""time"
)func main() {tick := time.Tick(100 * time.Millisecond)boom := time.After(500 * time.Millisecond)for {select {case <-tick:fmt.Println("tick.")case <-boom:fmt.Println("BOOM!")returndefault:fmt.Println("    .")time.Sleep(50 * time.Millisecond)}}
}

sync.Mutex

We’ve seen how channels are great for communication among goroutines.

But what if we don’t need communication? What if we just want to make sure only one goroutine can access a variable at a time to avoid conflicts?

This concept is called mutual exclusion, and the conventional name for the data structure that provides it is mutex.

Go’s standard library provides mutual exclusion with sync.Mutex and its two methods:

Lock
Unlock
We can define a block of code to be executed in mutual exclusion by surrounding it with a call to Lock and Unlock as shown on the Inc method.

We can also use defer to ensure the mutex will be unlocked as in the Value method.

package mainimport ("fmt""sync""time"
)// SafeCounter is safe to use concurrently.
type SafeCounter struct {v   map[string]intmux sync.Mutex
}// Inc increments the counter for the given key.
func (c *SafeCounter) Inc(key string) {c.mux.Lock()// Lock so only one goroutine at a time can access the map c.v.c.v[key]++c.mux.Unlock()
}// Value returns the current value of the counter for the given key.
func (c *SafeCounter) Value(key string) int {c.mux.Lock()// Lock so only one goroutine at a time can access the map c.v.defer c.mux.Unlock()return c.v[key]
}func main() {c := SafeCounter{v: make(map[string]int)}for i := 0; i < 1000; i++ {go c.Inc("somekey")}time.Sleep(time.Second)fmt.Println(c.Value("somekey"))
}// answer:1000

Exercise: Web Crawler

In this exercise you’ll use Go’s concurrency features to parallelize a web crawler.

Modify the Crawl function to fetch URLs in parallel without fetching the same URL twice.

Hint: you can keep a cache of the URLs that have been fetched on a map, but maps alone are not safe for concurrent use!

package mainimport ("fmt"
)type Fetcher interface {// Fetch returns the body of URL and// a slice of URLs found on that page.Fetch(url string) (body string, urls []string, err error)
}// Crawl uses fetcher to recursively crawl
// pages starting with url, to a maximum of depth.
func Crawl(url string, depth int, fetcher Fetcher) {// TODO: Fetch URLs in parallel.// TODO: Don't fetch the same URL twice.// This implementation doesn't do either:if depth <= 0 {return}body, urls, err := fetcher.Fetch(url)if err != nil {fmt.Println(err)return}fmt.Printf("found: %s %q\n", url, body)for _, u := range urls {Crawl(u, depth-1, fetcher)}return
}func main() {Crawl("https://golang.org/", 4, fetcher)
}// fakeFetcher is Fetcher that returns canned results.
type fakeFetcher map[string]*fakeResulttype fakeResult struct {body stringurls []string
}func (f fakeFetcher) Fetch(url string) (string, []string, error) {if res, ok := f[url]; ok {return res.body, res.urls, nil}return "", nil, fmt.Errorf("not found: %s", url)
}// fetcher is a populated fakeFetcher.
var fetcher = fakeFetcher{"https://golang.org/": &fakeResult{"The Go Programming Language",[]string{"https://golang.org/pkg/","https://golang.org/cmd/",},},"https://golang.org/pkg/": &fakeResult{"Packages",[]string{"https://golang.org/","https://golang.org/cmd/","https://golang.org/pkg/fmt/","https://golang.org/pkg/os/",},},"https://golang.org/pkg/fmt/": &fakeResult{"Package fmt",[]string{"https://golang.org/","https://golang.org/pkg/",},},"https://golang.org/pkg/os/": &fakeResult{"Package os",[]string{"https://golang.org/","https://golang.org/pkg/",},},
}

这个例子是6.824最初的版本。先读懂这个再去看crawler.go

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/382207.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

6.824 RPC lesson2 2020(一)

resources https://pdos.csail.mit.edu/6.824/notes/crawler.go https://pdos.csail.mit.edu/6.824/notes/l-rpc.txt https://pdos.csail.mit.edu/6.824/notes/kv.go RPC_concept 19 | 分布式通信之远程调用&#xff1a;我是你的千里眼&#xff08;https://time.geekbang.or…

6.824 RPC lesson2 2020(二)

Use RPC to make a kv storage server Go example: kv.go on schedule page A toy key/value storage server – Put(key,value), Get(key)->value Uses Go’s RPC library Common: Declare Args and Reply struct for each server handler. Client: connect()s Dial() cre…

35. 搜索插入位置 golang

题目 给定一个排序数组和一个目标值&#xff0c;在数组中找到目标值&#xff0c;并返回其索引。如果目标值不存在于数组中&#xff0c;返回它将会被按顺序插入的位置。 你可以假设数组中无重复元素。 示例 1: 输入: [1,3,5,6], 5 输出: 2 示例 2: 输入: [1,3,5,6], 2 输出…

191. 位1的个数 golang

题目 位1的个数 编写一个函数&#xff0c;输入是一个无符号整数&#xff0c;返回其二进制表达式中数字位数为 ‘1’ 的个数&#xff08;也被称为汉明重量&#xff09;。 示例 1&#xff1a; 输入&#xff1a;00000000000000000000000000001011 输出&#xff1a;3 解释&#…

445. 两数相加 II golang

题目 两数相加 II 给定两个非空链表来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储单个数字。将这两数相加会返回一个新的链表。 你可以假设除了数字 0 之外&#xff0c;这两个数字都不会以零开头。 进阶: 如果输入链表不能修改该如何处理&#xf…

关于golang的append函数的踩坑

文章目录从LeetCode第26题产生的疑问测试代码LeetCode22解决方式原题例2 LeetCode189copy的值复制从LeetCode第26题产生的疑问 这篇文章里面提到了关于在函数内部修改数据的情况。但是LeetCode22题中发现append无法在传送变量中进行append。 测试代码 输出结果 [123 456 7] //…

22. 括号生成 golang 图解

题目 括号生成 给出 n 代表生成括号的对数&#xff0c;请你写出一个函数&#xff0c;使其能够生成所有可能的并且有效的括号组合。 例如&#xff0c;给出 n 3&#xff0c;生成结果为&#xff1a; [ “((()))”, “(()())”, “(())()”, “()(())”, “()()()” ] 解法 f…

279. 完全平方数 golang BFS

题目 完全平方数 给定正整数 n&#xff0c;找到若干个完全平方数&#xff08;比如 1, 4, 9, 16, …&#xff09;使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。 示例 1: 输入: n 12 输出: 3 解释: 12 4 4 4. 示例 2: 输入: n 13 输出: 2 解释: 13 4 9…

104. 二叉树的最大深度 golang DFS

题目 二叉树的最大深度 给定一个二叉树&#xff0c;找出其最大深度。 二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。 说明: 叶子节点是指没有子节点的节点。 示例&#xff1a; 给定二叉树 [3,9,20,null,null,15,7]&#xff0c; 3/ \9 20/ \15 7返回它的最…

169. 多数元素 golang

题目 多数元素 给定一个大小为 n 的数组&#xff0c;找到其中的多数元素。多数元素是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。 你可以假设数组是非空的&#xff0c;并且给定的数组总是存在多数元素。 示例 1: 输入: [3,2,3] 输出: 3 示例 2: 输入: [2,2,1,1,1,2,2] 输出…

168.167Excle表列整数字符和字符整数的互相转化

题目 Excel表列序号 给定一个Excel表格中的列名称&#xff0c;返回其相应的列序号。 例如&#xff0c; A -> 1 B -> 2 C -> 3 ... Z -> 26 AA -> 27 AB -> 28 ...示例 1: 输入: “A” 输出: 1 示例 2: 输入: “AB” 输出: 28 示例 3: 输入: “ZY” 输…

709. 转换成小写字母 golang 字符串处理

题目 转换成小写字母 实现函数 ToLowerCase()&#xff0c;该函数接收一个字符串参数 str&#xff0c;并将该字符串中的大写字母转换成小写字母&#xff0c;之后返回新的字符串。 示例 1&#xff1a; 输入: “Hello” 输出: “hello” 示例 2&#xff1a; 输入: “here” 输…

9. 回文数 golang 整数处理

题目 9. 回文数 判断一个整数是否是回文数。回文数是指正序&#xff08;从左向右&#xff09;和倒序&#xff08;从右向左&#xff09;读都是一样的整数。 示例 1: 输入: 121 输出: true 示例 2: 输入: -121 输出: false 解释: 从左向右读, 为 -121 。 从右向左读, 为 121-…

28. 实现 strStr() golang

题目 28. 实现 strStr() 实现 strStr() 函数。 给定一个 haystack 字符串和一个 needle 字符串&#xff0c;在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在&#xff0c;则返回 -1。 示例 1: 输入: haystack “hello”, needle “ll” 输…

面试题57 - II. 和为s的连续正数序列 golang

题目 面试题57 - II. 和为s的连续正数序列 输入一个正整数 target &#xff0c;输出所有和为 target 的连续正整数序列&#xff08;至少含有两个数&#xff09;。 序列内的数字由小到大排列&#xff0c;不同序列按照首个数字从小到大排列。 示例 1&#xff1a; 输入&#x…

58. 最后一个单词的长度 golang string类的用法

题目 58. 最后一个单词的长度 给定一个仅包含大小写字母和空格 ’ ’ 的字符串 s&#xff0c;返回其最后一个单词的长度。 如果字符串从左向右滚动显示&#xff0c;那么最后一个单词就是最后出现的单词。 如果不存在最后一个单词&#xff0c;请返回 0 。 说明&#xff1a;一…

189. 旋转数组 golang

一个引出较多知识点的题 关于golang的append函数的踩坑 剑指offer-翻转字符串 557. 反转字符串中的单词 III 题目 189. 旋转数组 给定一个数组&#xff0c;将数组中的元素向右移动 k 个位置&#xff0c;其中 k 是非负数。 示例 1: 输入: [1,2,3,4,5,6,7] 和 k 3 输出: [5…

557. 反转字符串中的单词 III golang 数组和字符串反转

题目 189.反转数组 557. 反转字符串中的单词 III 557. 反转字符串中的单词 III LeetCode链接 给定一个字符串&#xff0c;你需要反转字符串中每个单词的字符顺序&#xff0c;同时仍保留空格和单词的初始顺序。 示例 1: 输入: “Let’s take LeetCode contest” 输出: “s’t…

198. 打家劫舍 golang 动态规划 数组越界

题目 198. 打家劫舍 你是一个专业的小偷&#xff0c;计划偷窃沿街的房屋。每间房内都藏有一定的现金&#xff0c;影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统&#xff0c;如果两间相邻的房屋在同一晚上被小偷闯入&#xff0c;系统会自动报警。 给定一个代…