In Go you can use a goKeywords make the program execute asynchronously
A more common scenario: calling multiple functions asynchronously one by one, or calling them asynchronously in a loop
If you understand the Go concurrency mechanism, you will know mainIt has ended before other goroutines have finished running, so the results of the above code are not as expected. We need to use a method called concurrency control to ensure that the program runs correctly
for example:
It is known that there is a ready-made function search, able to perform searches based on keywords
Expect to implement a new function coSearchAbility to perform batch queries
_63package main_63_63 _63_63import (_63_63"context"_63_63"errors"_63_63"fmt"_63_63"sync"_63_63)_63_63 _63_63func search(ctx context.Context, word string) (string, error) {_63_63if word == "Go" {_63_63return "", errors.New("error: Go") // 模拟结果_63_63}_63_63return fmt.Sprintf("result: %s", word), nil // 模拟结果_63_63}_63_63 _63_63func coSearch(ctx context.Context, words []string) (results []string, err error) {_63_63//tbd_63_63 _63_63return_63_63}_63_63 _63_63func main() {_63_63words := []string{"Go", "Rust", "PHP", "JavaScript", "Java"}_63_63results, err := coSearch(context.Background(), words)_63_63if err != nil {_63_63fmt.Println(err)_63_63return_63_63}_63_63 _63_63fmt.Println(results)_63_63}
sync.WaitGroupIt is a structure used to control concurrency in the Go standard library. Here is one for use WaitGroupaccomplish coSearchExample of
_116_116package main_116_116 _116_116import (_116_116"context"_116_116"errors"_116_116"fmt"_116_116"sync"_116_116)_116_116 _116_116func search(ctx context.Context, word string) (string, error) {_116_116if word == "Go" {_116_116return "", errors.New("error: Go") // 模拟结果_116_116}_116_116return fmt.Sprintf("result: %s", word), nil // 模拟结果_116_116}_116_116 _116_116func coSearch(ctx context.Context, words []string) ([]string, error) {_116_116var (_116_116wg = sync.WaitGroup{}_116_116once = sync.Once{}_116_116results = make([]string, len(words))_116_116err error_116_116)_116_116 _116_116for i, word := range words {_116_116wg.Add(1)_116_116 _116_116go func(word string, i int) {_116_116defer wg.Done()_116_116 _116_116result, e := search(ctx, word)_116_116if e != nil {_116_116once.Do(func() {_116_116err = e_116_116})_116_116 _116_116return_116_116}_116_116 _116_116results[i] = result_116_116}(word, i)_116_116}_116_116 _116_116wg.Wait()_116_116 _116_116return results, err_116_116}_116_116 _116_116func main() {_116_116words := []string{"Go", "Rust", "PHP", "JavaScript", "Java"}_116_116results, err := coSearch(context.Background(), words)_116_116if err != nil {_116_116fmt.Println(err)_116_116return_116_116}_116_116 _116_116fmt.Println(results)_116_116}
There are a lot of details in the above code, let’s talk about them one by one. sync.WaitGroupConcurrency control
sync.WaitGroup{}
The usage is very simple
-When a new goroutine is run, we need to call wg.Add(1)
-When a goroutine is finished running, we need to call wg.Done()
-wg.Wait()Let the program block here until all goroutines have finished running.
for coSearchIn
other words, waiting for all goroutines to complete, thus completing the task of the function and returning the final result.
_29var (_29_29wg = sync.WaitGroup{}_29_29//...省略其他代码_29_29)_29_29 _29_29for i, word := range words {_29_29wg.Add(1)_29_29 _29_29go func(word string, i int) {_29_29defer wg.Done()_29_29//...省略其他代码_29_29}(word, i)_29_29}_29_29 _29_29wg.Wait()
This is a classic Go error, if used in goroutine forIterative variables
, all goroutines will get the value of the last loop. For example, the following example does not output "a", "b", "c" but outputs "c", "c", "c"
_32_32func main() {_32_32done := make(chan bool)_32_32 _32_32values := []string{"a", "b", "c"}_32_32for _, v := range values {_32_32go func() {_32_32fmt.Println(v)_32_32done <- true_32_32}()_32_32}_32_32 _32_32// wait for all goroutines to complete before exiting_32_32for _ = range values {_32_32<-done_32_32}_32_32}