Go語言同步和非同步執行多個任務封裝

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

同步適合多個連續執行的,每一步的執行依賴於上一步操作,非同步執行則和任務執行順序無關(如從10個網站抓取資料)

同步執行類RunnerAsync

支援返回逾時檢測,系統中斷檢測

錯誤常量定義

//逾時錯誤var ErrTimeout = errors.New("received timeout")//作業系統系統中斷錯誤var ErrInterrupt = errors.New("received interrupt")

實現代碼如下

package taskimport (    "os"    "time"    "os/signal"    "sync")//非同步執行任務type Runner struct {    //作業系統的訊號檢測    interrupt chan os.Signal    //記錄執行完成的狀態    complete chan error    //逾時檢測    timeout <-chan time.Time    //儲存所有要執行的任務,順序執行    tasks []func(id int) error    waitGroup sync.WaitGroup    lock sync.Mutex    errs []error}//new一個Runner對象func NewRunner(d time.Duration) *Runner {    return &Runner{        interrupt: make(chan os.Signal, 1),        complete:  make(chan error),        timeout:   time.After(d),        waitGroup: sync.WaitGroup{},        lock:      sync.Mutex{},    }}//添加一個任務func (this *Runner) Add(tasks ...func(id int) error) {    this.tasks = append(this.tasks, tasks...)}//啟動Runner,監聽錯誤資訊func (this *Runner) Start() error {    //接收作業系統訊號    signal.Notify(this.interrupt, os.Interrupt)    //並發執行任務    go func() {        this.complete <- this.Run()    }()    select {    //返回執行結果    case err := <-this.complete:        return err        //逾時返回    case <-this.timeout:        return ErrTimeout    }}//非同步執行所有的任務func (this *Runner) Run() error {    for id, task := range this.tasks {        if this.gotInterrupt() {            return ErrInterrupt        }        this.waitGroup.Add(1)        go func(id int) {            this.lock.Lock()            //執行任務            err := task(id)            //加鎖儲存到結果集中            this.errs = append(this.errs, err)            this.lock.Unlock()            this.waitGroup.Done()        }(id)    }    this.waitGroup.Wait()    return nil}//判斷是否接收到作業系統中斷訊號func (this *Runner) gotInterrupt() bool {    select {    case <-this.interrupt:        //停止接收別的訊號        signal.Stop(this.interrupt)        return true        //正常執行    default:        return false    }}//擷取執行完的errorfunc (this *Runner) GetErrs() []error {    return this.errs}

  

使用方法    

Add添加一個任務,任務為接收int類型的一個閉包

Start開始執行傷,返回一個error類型,nil為執行完畢, ErrTimeout代表執行逾時,ErrInterrupt代表執行被中斷(類似Ctrl + C操作)

 

測試範例程式碼

package taskimport (    "testing"    "time"    "fmt"    "os"    "runtime")func TestRunnerAsync_Start(t *testing.T) {    //開啟多核    runtime.GOMAXPROCS(runtime.NumCPU())    //建立runner對象,設定逾時時間    runner := NewRunnerAsync(8 * time.Second)    //添加啟動並執行任務    runner.Add(        createTaskAsync(),        createTaskAsync(),        createTaskAsync(),        createTaskAsync(),        createTaskAsync(),        createTaskAsync(),        createTaskAsync(),        createTaskAsync(),        createTaskAsync(),        createTaskAsync(),        createTaskAsync(),        createTaskAsync(),        createTaskAsync(),    )    fmt.Println("同步執行任務")    //開始執行任務    if err := runner.Start(); err != nil {        switch err {        case ErrTimeout:            fmt.Println("執行逾時")            os.Exit(1)        case ErrInterrupt:            fmt.Println("任務被中斷")            os.Exit(2)        }    }    t.Log("執行結束")}//建立要執行的任務func createTaskAsync() func(id int) {    return func(id int) {        fmt.Printf("正在執行%v個任務\n", id)        //類比任務執行,sleep兩秒        //time.Sleep(1 * time.Second)    }}

執行結果

同步執行任務正在執行0個任務正在執行1個任務正在執行2個任務正在執行3個任務正在執行4個任務正在執行5個任務正在執行6個任務正在執行7個任務正在執行8個任務正在執行9個任務正在執行10個任務正在執行11個任務正在執行12個任務runnerAsync_test.go:49: 執行結束

  

 

非同步執行類Runner

支援返回逾時檢測,系統中斷檢測

實現代碼如下

package taskimport (    "os"    "time"    "os/signal"    "sync")//非同步執行任務type Runner struct {    //作業系統的訊號檢測    interrupt chan os.Signal    //記錄執行完成的狀態    complete chan error    //逾時檢測    timeout <-chan time.Time    //儲存所有要執行的任務,順序執行    tasks []func(id int) error    waitGroup sync.WaitGroup    lock sync.Mutex    errs []error}//new一個Runner對象func NewRunner(d time.Duration) *Runner {    return &Runner{        interrupt: make(chan os.Signal, 1),        complete:  make(chan error),        timeout:   time.After(d),        waitGroup: sync.WaitGroup{},        lock:      sync.Mutex{},    }}//添加一個任務func (this *Runner) Add(tasks ...func(id int) error) {    this.tasks = append(this.tasks, tasks...)}//啟動Runner,監聽錯誤資訊func (this *Runner) Start() error {    //接收作業系統訊號    signal.Notify(this.interrupt, os.Interrupt)    //並發執行任務    go func() {        this.complete <- this.Run()    }()    select {    //返回執行結果    case err := <-this.complete:        return err        //逾時返回    case <-this.timeout:        return ErrTimeout    }}//非同步執行所有的任務func (this *Runner) Run() error {    for id, task := range this.tasks {        if this.gotInterrupt() {            return ErrInterrupt        }        this.waitGroup.Add(1)        go func(id int) {            this.lock.Lock()            //執行任務            err := task(id)            //加鎖儲存到結果集中            this.errs = append(this.errs, err)            this.lock.Unlock()            this.waitGroup.Done()        }(id)    }    this.waitGroup.Wait()    return nil}//判斷是否接收到作業系統中斷訊號func (this *Runner) gotInterrupt() bool {    select {    case <-this.interrupt:        //停止接收別的訊號        signal.Stop(this.interrupt)        return true        //正常執行    default:        return false    }}//擷取執行完的errorfunc (this *Runner) GetErrs() []error {    return this.errs}

  

使用方法    

Add添加一個任務,任務為接收int類型,傳回型別error的一個閉包

Start開始執行傷,返回一個error類型,nil為執行完畢, ErrTimeout代表執行逾時,ErrInterrupt代表執行被中斷(類似Ctrl + C操作)

getErrs擷取所有的任務執行結果

 

測試範例程式碼

package taskimport (    "testing"    "time"    "fmt"    "os"    "runtime")func TestRunner_Start(t *testing.T) {    //開啟多核心    runtime.GOMAXPROCS(runtime.NumCPU())    //建立runner對象,設定逾時時間    runner := NewRunner(18 * time.Second)    //添加啟動並執行任務    runner.Add(        createTask(),        createTask(),        createTask(),        createTask(),        createTask(),        createTask(),        createTask(),        createTask(),        createTask(),        createTask(),        createTask(),        createTask(),        createTask(),        createTask(),    )    fmt.Println("非同步執行任務")    //開始執行任務    if err := runner.Start(); err != nil {        switch err {        case ErrTimeout:            fmt.Println("執行逾時")            os.Exit(1)        case ErrInterrupt:            fmt.Println("任務被中斷")            os.Exit(2)        }    }    t.Log("執行結束")    t.Log(runner.GetErrs())}//建立要執行的任務func createTask() func(id int) error {    return func(id int) error {        fmt.Printf("正在執行%v個任務\n", id)        //類比任務執行,sleep        //time.Sleep(1 * time.Second)        return nil    }}

執行結果

非同步執行任務正在執行2個任務正在執行1個任務正在執行4個任務正在執行3個任務正在執行6個任務正在執行5個任務正在執行9個任務正在執行7個任務正在執行10個任務正在執行13個任務正在執行8個任務正在執行11個任務正在執行12個任務正在執行0個任務runner_test.go:49: 執行結束runner_test.go:51: [<nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil>]

  

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.