一個備份任務分發的Golang實現原型

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

       前段在玩協程時跟著libtask的作者Russ Cox轉到Golang了,一堆重量級大牛們想出來的東西就是不同,思路非常特別,和常用的差別有點大,

但非常注重實用,減少了一堆的文法糖後,讓人重新思考,開發語言本來應當是怎麼樣?如果用來做服務端開發的話,真的是很不錯的東西。

       在一個練習中,我設計了個發送OracleDatabase Backup任務的簡單情境。通過 發送備份任務到各個用戶端,來練習Golang中的sync.WaitGroup.

       sync.WaitGroup是Golang提供的一種簡單的同步方法集合。它有三個方法.
             Add() 添加計數,數目可以為一個,也可以為多個。
             Done() 減掉一個計數,如果計數不為0,則Wait()會阻塞在那,直到全部為0
             Wait() 等待計數為0.

 

         弄個例子直觀的見識下:

package mainimport ("fmt""sync")var waitGrp sync.WaitGroupfunc main() {bakJobs := []string{"Full Database", "Archive Log", "Control File"}for i := 0; i < len(bakJobs); i++ {waitGrp.Add(1) //add jobgo func(jobName string) {fmt.Println(jobName)waitGrp.Done() //sub job}(bakJobs[i])}waitGrp.Wait()}/*E:\GitHub\Golang\XCLTools\src\test>wgFull DatabaseArchive LogControl File*/
可以看到會依次列印bakJobs中的資料。但如果把waitGrp.Wait()注釋掉。啥都不會輸出。即,在for後,wait會等待所有的job執行完後,

才會執行後面的。  這個例子說明,除了熟悉了下waitGroup的使用外,還說明waitGroup能保證作業的執行順序,及會等待所有子作業全部完成再繼續的特性。

       就OracleDatabase Backup本身而言,在這使用go func()...其實意義不大,所以我想了個更複雜點的情境,給多個伺服器上的資料庫批量發送備份指令,並依資料庫

的重要性順序來執行。

      下面是實現的代碼(純示範,忽略掉其它通訊和邏輯處理方面的東西):       

package mainimport ("fmt""sync")var waitGrp sync.WaitGroupfunc main() {waitGrp.Add(2)for _, ip := range []string{"ip1", "ip2"} {go doJobs(ip)fmt.Println("IP = ", ip)}waitGrp.Wait()fmt.Println("main() end.")}func doJobs(ip string) {bakJobs := []string{"Full Database", "Archive Log", "Control File"}for i := 0; i < len(bakJobs); i++ {doBak(ip, i, bakJobs[i])}fmt.Println("The backup is complete!")fmt.Println("......")defer waitGrp.Done()}func doBak(ip string, id int, jobName string) (bool, error) {fmt.Println("doBak() :", ip, " - ", id, " - ", jobName)return true, nil}/*IP =  ip1IP =  ip2doBak() : ip1  -  0  -  Full DatabasedoBak() : ip1  -  1  -  Archive LogdoBak() : ip1  -  2  -  Control FileThe backup is complete!......doBak() : ip2  -  0  -  Full DatabasedoBak() : ip2  -  1  -  Archive LogdoBak() : ip2  -  2  -  Control FileThe backup is complete!......main() end.*/

    代碼中,會首先向各個IP發送執行jobs的指令。各個指令執行的時間有長有短,用go func()...能保證是在同一時間向所有相關IP發出命令讓各IP依次執行相關備份。

主goroutine則等待這個總作業全部結束後再執行其它。同時由於waitGroup的順序性,能保證重要點的ip,可以優先執行。

    我設計情境的目的是想在例子中加入更多的Golang新鮮元素來增強感覺,所以針對上一個例子,我又設想了一個情況,因為Database Backup是很耗時的,且要等待

所有IP上的作業都執行完畢要花費很長時間,如果這時,使用者要求取消這次作業怎麼辦?

    於是這就有了下面的例子:

package mainimport ("bufio""fmt""os""sync""time")var waitGrp sync.WaitGroupfunc main() {ch := make(chan bool)go schedule(ch)r := bufio.NewReader(os.Stdin)for {time.Sleep(time.Second)fmt.Print("Command:> ")ln, _, _ := r.ReadLine()cmd := string(ln)if "q" == cmd || "quit" == cmd {close(ch)break} else {fmt.Println(" = cmd = ", cmd, "\n")}}waitGrp.Wait()fmt.Println("main() end.")}func schedule(ch chan bool) {for _, ip := range []string{"ip1", "ip2"} {waitGrp.Add(1)go doJobs(ip, ch)fmt.Println("schedule() IP = ", ip)}fmt.Println("schedule() end.")return}func doJobs(ip string, ch chan bool) {defer waitGrp.Done()for i := 0; i < 10; i++ {select {case <-ch:fmt.Println("doJobs() ", ip, "=>Job Cancel......")returndefault:}fmt.Println("doJobs()...... ", ip, " for:", i)time.Sleep(time.Second)}}/*E:\GitHub\Golang\XCLTools\src\test>wg5schedule() IP =  ip1schedule() IP =  ip2schedule() end.doJobs()......  ip1  for: 0doJobs()......  ip2  for: 0Command:> doJobs()......  ip1  for: 1doJobs()......  ip2  for: 1doJobs()......  ip1  for: 2doJobs()......  ip2  for: 2doJobs()......  ip1  for: 3doJobs()......  ip2  for: 3doJobs()......  ip1  for: 4doJobs()......  ip2  for: 4doJobs()......  ip1  for: 5doJobs()......  ip2  for: 5doJobs()......  ip1  for: 6doJobs()......  ip2  for: 6doJobs()......  ip1  for: 7doJobs()......  ip2  for: 7doJobs()......  ip1  for: 8doJobs()......  ip2  for: 8doJobs()......  ip1  for: 9doJobs()......  ip2  for: 9qmain() end.E:\GitHub\Golang\XCLTools\src\test>wg5schedule() IP =  ip1schedule() IP =  ip2schedule() end.doJobs()......  ip1  for: 0doJobs()......  ip2  for: 0Command:> doJobs()......  ip2  for: 1doJobs()......  ip1  for: 1doJobs()......  ip2  for: 2doJobs()......  ip1  for: 2doJobs()......  ip2  for: 3doJobs()......  ip1  for: 3qdoJobs()  ip2 =>Job Cancel......doJobs()  ip1 =>Job Cancel......main() end.*/
        我用了個for{},讓使用者在作業執行過程中,可以輸入指令退出執行。並且,在退出過程中,各個IP也會作相關的取消處理。以保證不會因

強制中斷而出現一些不必要的麻煩。

   這個例子到這,已經引入了足夠多的東西,我覺得已達到練習的目的,情境就先到此了。

   在此整理下,以備後查。


   MAIL:  xcl_168@aliyun.com

  BLOG: http://blog.csdn.net/xcl168


相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.