這是一篇使用併發和通道來實現控制程式生命週期的併發模式示例,該示例演示了如何控制程式在規定時間段內的執行,並可以手動中斷來終止程式的執行。展示如何通過通道來監視程式的執行時間,如果程式執行時間過長,也可以終止程式
當需要排程後台處理任務的時候,這種模式會很有用。該程式可能會作為 cron 作業執行,或者在基於定時任務的雲環境 (如 裡執行。
建立乙個執行者 runner, 給 runner 設定乙個超時時間 timeout 和任務切片 tasks,然後遍歷執行 tasks 所有任務。
設定乙個儲存中斷訊號的字段 interrupt,通過 interrupt 來判斷是否已經中斷程式。
設定乙個記錄每個任務執行錯誤結果的字段 complete,監聽 complete, 判斷是那種錯誤型別,然後做相應的處理。
執行所有任務,並監聽不同錯誤碼,執行不同的業務邏輯。
首先我們需要宣告乙個 runner 結構
type runner struct
runner 中包括任務切片 tasks, tasks 是乙個儲存 func(int) 型別的切片,後面會遍歷 tasks 來進行處理任務。
timeout 欄位是乙個存放超時時間的唯讀的通道,通過該字段來判斷任務執行是否超時。
interrupt 欄位是存放 os.signal 型別的通道,接收到來自終端的中斷訊號會存放在該字段中。
complete 欄位是存放任務執行的錯誤結果,如果沒有錯誤則是 nil。
有了 runner 執行者這個結構後,我們可以宣告乙個 new 工廠函式來建立 runner 型別的物件,並初始化需要的字段。
// 工廠函式建立 runner
func new(timeout time.duration) *runner
}
建立 runner 的時候,我們需要傳入乙個 time.duration 型別的引數,然後內部呼叫 time.after() 這個函式來返回乙個time.time 型別的唯讀通道。interrupt 和 complete 字段正常初始化即可。tasks 預設是空切片(表示還沒有任何任務)。
有了乙個 runner 執行者物件後,在執行任務之前我們需要給 runner 的增加任務,那我們需要寫乙個給 runner 增加任務的方法。
// 增加任務
// 可變引數 ...func(int) 表示引數可以是多個引數
func (r *runner) add(tasks ...func(int))
增加任務方法 add 接收乙個引數型別為 func(int) 的可變引數,可變引數意味著引數的數量是可變的,可以是單個,也可以是多個。
當呼叫 add 方法後,就會把傳入的引數賦值給 runner 型別物件的 tasks 字段,此時 runner 型別物件就有任務了。
因為任務執行過程會有多個錯誤值,比如超時錯誤和中斷錯誤,所以我們先定義兩個錯誤變數,以備後面使用。
// 錯誤型別
var (
errtimeout = errors.new("超時錯誤")
errinterrupt = errors.new("程式中斷錯誤")
)
接下來就是任務的執行。
// 執行任務
func (r *runner) run() error
task(id)
} return nil
}
執行任務就是遍歷runner 物件中的 tasks 的所有任務,然後執行每乙個任務即可,但是在執行任務之前,需要判斷是否已經中斷了程式。如果已經中斷了程式,則直接返回中斷錯誤 errinterrupt。
以下是判斷程式中斷的方法
// 判斷是否中斷程式
func (r *runner) isinterrupt() bool
}
該方法是 runner 型別的乙個方法,方法內使用了 select 多路復用來進行監聽
interrupt 通道是否有中斷訊號,如果監聽到有中斷訊號,則任務是使用者中斷了程式,此時會呼叫 signal.stop() 方法 中斷程式,然後返回 true ,表示程式已經被中斷。
接下來,我們的實現乙個方法來整合整個任務執行的流程,包括任務的執行,中斷和超時的監聽。
// 執行所有任務,並監聽通道事件
func (r *runner) start() error ()
select
}
start 方法中,會接收所有的中斷訊號,放在 interrupt 通道中,然後呼叫 run 方法來執行所有任務,並把執行的結果存放到 complete 通道中,最後通過 select 多路復用方式監聽 complete 通道和 timeout 通道中的訊息,一旦有錯誤就返回錯誤碼。
執行者呼叫 start 方法後拿到錯誤碼,執行自己的業務邏輯,如果沒有錯誤碼返回則表示所有任務在規定的超時時間內成功執行了所有任務。
目前所有任務的執行,錯誤碼監聽等工作已經全部完成。
接下來我們建立乙個 runner 物件來驗證一下程式。
func main()
} fmt.println("程式結束")
}
因為 add 方法引數要求是乙個傳入 int 型別的函式,所以為了方便建立任務,我們宣告乙個使用了閉包的 createtask 函式來返回任務函式。
// 建立任務
func createtask() func(int)
}
到目前為止所有的**實現已經全部編寫完成
package main
import (
"errors"
"fmt"
"os"
"os/signal"
"time")
type runner struct
// 工廠函式建立 runner
func new(timeout time.duration) *runner }
// 錯誤型別
var (
errtimeout = errors.new("超時錯誤")
errinterrupt = errors.new("程式中斷錯誤"))
// 執行任務
func (r *runner) run() error
task(id)
} return nil}
// 判斷是否中斷程式
func (r *runner) isinterrupt() bool }
// 增加任務
// 可變引數 ...func(int) 表示引數可以是多個引數
func (r *runner) add(tasks ...func(int))
// 執行所有任務,並監聽通道事件
func (r *runner) start() error ()
select }
// 建立任務
func createtask() func(int) }
func main()
} fmt.println("程式結束")
瓦力視覺控制程式
上位機是採用了aforge.net framework 2.2.3和ez b sdk windows v2011.11.09.00的結合。aforge真的很強大,不過沒有涉及到控制這塊,ezb就有現成的參考,但ezb沒有提供核心部分的 而它只支援本地攝像頭,所以我只能反編譯獲取需要的 移植到afor...
瓦力視覺控制程式
2012 01 30 上位機是採用了aforge.net framework 2.2.3和ez b sdk windows v2011.11.09.00的結合。aforge真的很強大,不過沒有涉及到控制這塊,ezb就有現成的參考,但ezb沒有提供核心部分的 而它只支援本地攝像頭,所以我只能反編譯獲取...
Access使用巨集控制程式
巨集是指乙個或多個www.cppcns.com操作的集合,其中每個操作實現特定的功能,例如開啟某個窗體或列印某個報表。巨集可以使某些普通的任務自動完成。例如,可設定某個巨集,在使用者單擊某個命令程式設計客棧按鈕cvpbmstdwj時執行該巨集,以開啟某個窗體程式設計客棧。巨集可以是包含操作序列的乙個...