Go語(yǔ)言并發(fā)范式之future模式詳解
1、Go語(yǔ)言并發(fā)范式-future模式
編程中經(jīng)常遇到在一個(gè)流程中需要調(diào)用多個(gè)子調(diào)用的情況,這些子調(diào)用相互之間沒(méi)有依賴,如果串行地調(diào)用,則耗時(shí)會(huì)很長(zhǎng),此時(shí)可以使用Go并發(fā)編程中的future模式。
future模式的基本工作原理:
(1)、使用chan作為函數(shù)參數(shù)。
(2)、啟動(dòng)goroutine調(diào)用函數(shù)。
(3)、通過(guò)chan傳入?yún)?shù)。
(4)、做其他可以并行處理的事情。
(5)、通過(guò)chan異步獲取結(jié)果。
package main import ( "fmt" "time" ) // 一個(gè)查詢結(jié)構(gòu)體 // 這里的sql和result是一個(gè)簡(jiǎn)單的抽象,具體的應(yīng)用,可能是更復(fù)雜的數(shù)據(jù)類型 type query struct { //參數(shù)Channel sql chan string //結(jié)果Channel result chan string } //執(zhí)行Query func execQuery(q query) { //啟動(dòng)協(xié)程 go func() { //獲取輸入 sql := <-q.sql //訪問(wèn)數(shù)據(jù)庫(kù) //輸出結(jié)果通道 q.result <- "result from " + sql }() } func main() { //初始化Query q := query{make(chan string, 1), make(chan string, 1)} //執(zhí)行Query,注意執(zhí)行的時(shí)候無(wú)需準(zhǔn)備參數(shù) go execQuery(q) //準(zhǔn)備參數(shù) q.sql <- "select * from table;" //do otherthings time.Sleep(1 * time.Second) //獲取結(jié)果 fmt.Println(<-q.result) }
程序輸出
result from select * from table;
future最大的好處是將函數(shù)的同步調(diào)用轉(zhuǎn)換為異步調(diào)用,適用于一個(gè)交易需要多個(gè)子調(diào)用且這些子調(diào)用沒(méi)有依賴
的場(chǎng)景。實(shí)際情況可能比上面示例復(fù)雜得多,要考慮錯(cuò)誤和異常的處理,讀者著重體驗(yàn)這種思想,而不是細(xì)節(jié)。
2、Future模式的實(shí)現(xiàn)步驟
(1)、構(gòu)建結(jié)構(gòu)體FutureTask
這里我們將要做的事情抽象成任務(wù),對(duì)于每個(gè)任務(wù)我們可能需要傳遞參數(shù)過(guò)去,并且我們還需要得到這個(gè)任務(wù)的執(zhí)行結(jié)果,為此,我們創(chuàng)建兩個(gè)channel,一個(gè)用于傳遞參數(shù),一個(gè)用于保存結(jié)果。(具體還需要什么其他的參數(shù)可以根據(jù)具體業(yè)務(wù)進(jìn)行設(shè)計(jì))。
// FutureTask 在并發(fā)執(zhí)行時(shí)用于傳遞參數(shù)和保存返回的結(jié)果 type FutureTask struct { // 用于傳遞參數(shù) args chan interface{} // 實(shí)際業(yè)務(wù)中可能還有很多其他的數(shù)據(jù) // 用于保存結(jié)果 res chan interface{} }
(2)、創(chuàng)建goroutine執(zhí)行future的方法
在創(chuàng)建好FutureTask之后,需要開(kāi)啟goroutine去執(zhí)行,為此需要?jiǎng)?chuàng)建一個(gè)執(zhí)行FutureTask的方法:
// execFutureTask 用于開(kāi)啟一個(gè)Future模式的線程 func execFutureTask(futureTask *FutureTask) { // 讀取傳入的參數(shù) fmt.Println("goroutine讀取到的參數(shù):", <-futureTask.args) // 這里可以執(zhí)行具體的業(yè)務(wù)邏輯 result := "執(zhí)行完業(yè)務(wù)邏輯后得到的結(jié)果" // 將結(jié)果進(jìn)行保存 futureTask.res <- result defer close(futureTask.res) return }
(3)、測(cè)試代碼
package main import ( "fmt" "time" ) // FutureTask 在并發(fā)執(zhí)行時(shí)用于傳遞參數(shù)和保存返回的結(jié)果 type FutureTask struct { // 用于傳遞參數(shù) args chan interface{} // 實(shí)際業(yè)務(wù)中可能還有很多其他的數(shù)據(jù) // 用于保存結(jié)果 res chan interface{} } // execFutureTask 用于開(kāi)啟一個(gè)Future模式的線程 func execFutureTask(futureTask *FutureTask) { // 讀取傳入的參數(shù) fmt.Println("goroutine讀取到的參數(shù):", <-futureTask.args) // 這里可以執(zhí)行具體的業(yè)務(wù)邏輯 result := "執(zhí)行完業(yè)務(wù)邏輯后得到的結(jié)果" // 將結(jié)果進(jìn)行保存 futureTask.res <- result defer close(futureTask.res) return } func main() { // 創(chuàng)建一個(gè)FutureTask并開(kāi)啟一個(gè)goroutine去執(zhí)行 futureTask := FutureTask{make(chan interface{}), make(chan interface{})} go execFutureTask(&futureTask) // 向FutureTask傳入?yún)?shù),如果不傳的話會(huì)死鎖 futureTask.args <- "main線程傳入的參數(shù)" // 這里可以并行的去執(zhí)行一些其他業(yè)務(wù)邏輯 time.Sleep(1 * time.Second) // 讀取線程執(zhí)行的 fmt.Println("主線程讀取future模式下goroutine的結(jié)果:", <-futureTask.res) }
(4)、執(zhí)行結(jié)果
程序輸出
goroutine讀取到的參數(shù): main線程傳入的參數(shù)
主線程讀取future模式下goroutine的結(jié)果: 執(zhí)行完業(yè)務(wù)邏輯后得到的結(jié)果
(5)、完整代碼
package main import ( "fmt" "time" ) // FutureTask 在并發(fā)執(zhí)行時(shí)用于傳遞參數(shù)和保存返回的結(jié)果 type FutureTask struct { // 用于傳遞參數(shù) args chan interface{} // 實(shí)際業(yè)務(wù)中可能還有很多其他的數(shù)據(jù) // 用于保存結(jié)果 res chan interface{} } // execFutureTask 用于開(kāi)啟一個(gè)Future模式的線程 func execFutureTask(futureTask *FutureTask) { // 讀取傳入的參數(shù) fmt.Println("goroutine讀取到的參數(shù):", <-futureTask.args) // 這里可以執(zhí)行具體的業(yè)務(wù)邏輯 result := "執(zhí)行完業(yè)務(wù)邏輯后得到的結(jié)果" // 將結(jié)果進(jìn)行保存 futureTask.res <- result defer close(futureTask.res) return } func main() { // 創(chuàng)建一個(gè)FutureTask并開(kāi)啟一個(gè)goroutine去執(zhí)行 futureTask := FutureTask{make(chan interface{}), make(chan interface{})} go execFutureTask(&futureTask) // 向FutureTask傳入?yún)?shù),如果不傳的話會(huì)死鎖 futureTask.args <- "main線程傳入的參數(shù)" // 這里可以并行的去執(zhí)行一些其他業(yè)務(wù)邏輯 time.Sleep(1 * time.Second) // 讀取線程執(zhí)行的 fmt.Println("主線程讀取future模式下goroutine的結(jié)果:", <-futureTask.res) }
到此這篇關(guān)于Go語(yǔ)言并發(fā)范式之future模式詳解的文章就介紹到這了,更多相關(guān)Go future模式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
go語(yǔ)言調(diào)用其他包中的函數(shù)簡(jiǎn)單示例
這篇文章主要給大家介紹了關(guān)于go語(yǔ)言調(diào)用其他包中的函數(shù)的相關(guān)資料,文中還介紹了Go語(yǔ)言同一個(gè)包中不同文件之間函數(shù)調(diào)用的相關(guān)問(wèn)題,需要的朋友可以參考下2023-01-01axios?gin的GET和POST請(qǐng)求實(shí)現(xiàn)示例
這篇文章主要為大家介紹了axios?gin的GET和POST請(qǐng)求實(shí)現(xiàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04完美解決go Fscanf 在讀取文件時(shí)出現(xiàn)的問(wèn)題
這篇文章主要介紹了完美解決go Fscanf 在讀取文件時(shí)出現(xiàn)的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-03-03Golang Gin框架實(shí)現(xiàn)文件下載功能的示例代碼
本文主要介紹了Golang Gin框架實(shí)現(xiàn)文件下載功能的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-12-12如何在Go語(yǔ)言中高效使用Redis的Pipeline
在 Redis 中,Pipeline 就像一條流水線,它允許我們將多個(gè)命令一次性發(fā)送到服務(wù)器,下面我們就來(lái)看看如何在Go語(yǔ)言中高效使用Redis的Pipeline吧2024-11-11