Single task only
Global resource loading (initialization), public resource destruction in multitasking
// Initialization work // 1. Through init method, it is only executed once, but cannot be called repeatedly // Simulate global configuration type AppConfig struct { Name string IP string Version string } var appconfig *AppConfig func init() { appconfig=new(AppConfig) appconfig.Name = "myapp" appconfig.IP = "192.168.66.88" appconfig.Version="v1.0" } // 2. Use the sync.once method to ensure that our code is executed once // Destroy global resources var once sync.Once func DelAPP() { once.Do(func(){ appconfig = nil log.Println("delete app!") }) }
Writing asynchronous methods
If the task takes a long time, you can consider writing the method asynchronously (similar to ajax request in front-end knowledge), for example, if there is a task in the task that needs to be downloaded, then the download task can consider writing asynchronously, such as data storage task, etc
Key points of writing asynchronous task method: start goroutine to process the task within the task, and return immediately >
// Write a database asynchronous processing task (simulation) func StorageData(data string){ // Preprocessing data log.Println("Pretreatment before warehousing: ",data) go func(data){ time.Sleep(time.Sencond*3) log.Println("Database storage complete") } }
Write asynchronous callback method
Based on the asynchronous method, if you want to process the asynchronous result, you need to pass a callback method
Note: on the basis of writing asynchrony, add callback method (processing result)
// Writing an asynchronous web crawling method package main import ( "io/ioutil" "log" "net/http" "os" "time" ) func CrawlUrl(url string,fn func(response *http.Response)) { go func() { response,err:=http.Get(url) if err!=nil{ log.Println(err) return } fn(response) }() } func main() { CrawlUrl("http://www.baidu.com", func(response *http.Response) { data,err:=ioutil.ReadAll(response.Body) if err!=nil{ return } log.Println("Content length: ",len(data)) }) log.Println("main func do other thing") CrawlUrl("http://i2.hdslb.com/bfs/archive/bc8adff1dafe7494c6b2155ec82725af0034c31b.png", func(response *http.Response) { data,err:=ioutil.ReadAll(response.Body) if err!=nil{ log.Println(err) return } f,_:=os.Create("1.png") defer f.Close() _, _ = f.Write(data) }) time.Sleep(time.Second*5) }
Wait for all tasks to finish
Start multiple subtasks and wait for subtasks to finish
No results required
Need results
// 1. You need to return results, just complete the task func CallTaskNoRsult(){ wg := sync.WaitGroup{} wg.Add(5) for i:=0;i<5;i++{ go func(num int) { defer wg.Done() log.Println("task",num,"complete") }(i) } wg.Wait() } // 2. You need to complete the task and return the result, which may need to be processed later func CallTaskResults() { // Create a channel to receive task processing results results:=make(chan string,10) defer close(results) // Random seed rand.Seed(time.Now().UnixNano()) for i:=0;i<10;i++{ go func(num int) { // Randomly generate a result and add the result to the result queue results<-fmt.Sprintf("Task %d# result: %d",num,rand.Intn(20)+10) }(i) } //Wait for output for i:=0;i<10;i++{ log.Println(<-results) } }
Wait for any task to complete
If there are multiple download sources and it is not sure which source network is in good condition, this method can be considered.
// Simulate multi-source download, and any task will be completed func Download(){ // Define a channel to receive results result:=make(chan string) defer close(result) // seed rand.Seed(time.Now().UnixNano()) // Get download data of subtask asynchronously for i:=0;i<10;i++{ go func(num int) { // Sleep randomly for a period of time time.Sleep(time.Second*time.Duration(rand.Intn(5)+1)) result<-fmt.Sprintf("Task %d# download ok!",num) }(i) } // Wait for subtask to complete log.Println(<-result) }
Collaboration waiting for other task results
Some businesses with a little complexity, one of which requires the results of another subtask
// Asynchronous collaboration, Task B needs task calculation results func BWaitA() { // Create channel for task communication ch:=make(chan string,1) // Caching is 1 defer close(ch) // Create a wait group wg:= sync.WaitGroup{} wg.Add(2) // Start task A go func() { defer wg.Done() log.Println("A do working...") time.Sleep(time.Second*3) log.Println("A end calc...., send result to B") ch<-"data for B" log.Println("A do send result to B, do other thing!") }() // Start task B go func() { defer wg.Done() log.Println("B do working...") time.Sleep(time.Second*2) log.Println("B wait A...") log.Println(<-ch) log.Println("B user A result do other thing!") }() wg.Wait() }
Task cancellation
In some special situations, we may need to cancel the execution of subtasks, for example, the main task needs to be terminated in advance due to the user's reason, and all subtasks should be notified to end
Single level task cancellation
func CancleTask() { // Create a cancel channel to notify the subtask to end canncle:=make(chan struct{}) // Encapsulates a method to check whether the task has been cancelled iscancle:= func() bool { select { case <-canncle: return true default: return false } } //Simulation start subtask for i:=0;i<5;i++{ go func(num int) { for{ // Whether the listening task is cancelled if iscancle(){ // Exit task if cancelled log.Printf("Task #%d is canceled!\n",num) return } log.Printf("Task #%d is working...\n",num) time.Sleep(time.Millisecond *50) } }(i) } // Simulation task runs for a period of time log.Println("main working for an while...") time.Sleep(time.Millisecond *100) // Cancel the task and turn off the broadcast feature of the channel close(canncle) time.Sleep(time.Second) }
Multi level task cancellation
When the task is more complex, it may be related tasks, such as multi-level tasks as shown in the figure below
A preliminary understanding of Context
-
For the root context node, context. Backgoud() creates an empty context (root node), which has no effect. In order to inherit the
-
ctx, cancel: = context.withcancel (ctx), return a ctx child node, return a cancelfuc
-
Call cancel method to send cancel signal to all child nodes
-
Listen for cancel signal in subtask and exit the task
Cancel task with context
func CancelWithCtx() { // Create empty ctx, root node root:=context.Background() // Define isCancel method isCanncel:= func(ctx context.Context) bool { select { case <-ctx.Done(): return true default: return false } } Task:=func (ctx context.Context, num int){ // Start subtask go func() { for{ if isCanncel(ctx){ // Exit task if cancelled log.Printf("Task #%d sub is canceled!\n",num) return } } }() for{ if isCanncel(ctx){ // Exit task if cancelled log.Printf("Task #%d is canceled!\n",num) return } log.Printf("Task #%d is working...\n",num) time.Sleep(time.Millisecond*200) } } // Create child ctx to cancel ctxOne,cancelOne:=context.WithCancel(root) go Task(ctxOne,1) // Create child ctx to cancel ctxTwo,_:=context.WithCancel(root) go Task(ctxTwo,2) // Simulation ensures that all goroutine s are running time.Sleep(time.Second) // Cancel first task cancelOne() time.Sleep(time.Second) }
output:
2019/06/27 11:55:45 Task #1 is working... 2019/06/27 11:55:45 Task #2 is working... 2019/06/27 11:55:46 Task #1 is working... 2019/06/27 11:55:46 Task #2 is working... 2019/06/27 11:55:46 Task #1 is working... 2019/06/27 11:55:46 Task #2 is working... 2019/06/27 11:55:46 Task #1 is working... 2019/06/27 11:55:46 Task #2 is working... 2019/06/27 11:55:46 Task #1 is working... 2019/06/27 11:55:46 Task #2 is working... 2019/06/27 11:55:46 Task #1 sub is canceled! 2019/06/27 11:55:46 Task #1 is canceled! 2019/06/27 11:55:46 Task #2 is working... 2019/06/27 11:55:47 Task #2 is working... 2019/06/27 11:55:47 Task #2 is working... 2019/06/27 11:55:47 Task #2 is working... 2019/06/27 11:55:47 Task #2 is working...
The demonstration of context in net/http package
package main import ( "fmt" "net/http" "time" ) func CtxTest(w http.ResponseWriter, r *http.Request){ // Get ctx ctx := r.Context() fmt.Println("processing request") select { case <-time.After(5 * time.Second): // Simulation request processing completed w.Write([]byte("request processed")) case <-ctx.Done(): // When the web page is loaded, the Done signal is sent // When the user cancels, obtain the cancellation signal s fmt.Println( "request cancelled") } } func main() { // Binding route processing method http.HandleFunc("/",CtxTest) // Startup service http.ListenAndServe(":8000", nil) }