欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

golang Goroutine超時(shí)控制的實(shí)現(xiàn)

 更新時(shí)間:2023年09月14日 10:10:26   作者:一個(gè)搬磚的程序猿  
日常開(kāi)發(fā)中我們大概率會(huì)遇到超時(shí)控制的場(chǎng)景,比如一個(gè)批量耗時(shí)任務(wù)、網(wǎng)絡(luò)請(qǐng)求等,本文主要介紹了golang Goroutine超時(shí)控制的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

1.個(gè)人理解 

package main
import (
	"context"
	"fmt"
	"runtime"
	"time"
)
func main() {
	// 為了方便查看設(shè)置的計(jì)數(shù)器
	//go func() {
	//	var o int64
	//	for {
	//		o++
	//		fmt.Println(o)
	//		time.Sleep(time.Second)
	//	}
	//}()
	// 開(kāi)啟協(xié)程
	for i := 0; i < 100; i++ {
		go func(i int) {
			// 利用context 設(shè)置超時(shí)上下文
			ctx, cancel := context.WithTimeout(context.TODO(), 2*time.Second)
			// 主動(dòng)退出信號(hào)
			endDone := make(chan struct{})
			// 再次開(kāi)啟子協(xié)程異步處理業(yè)務(wù)邏輯
			go func() {
				select {
				// 監(jiān)聽(tīng)是否超時(shí)
				case <-ctx.Done():
					fmt.Println("Goroutine timeout")
					return
				// 處理業(yè)務(wù)邏輯
				default:
					if i == 1 {
						time.Sleep(10 * time.Second)
					}
					// 此處代碼會(huì)繼續(xù)執(zhí)行
					//fmt.Println("代碼邏輯繼續(xù)執(zhí)行")
					// 主動(dòng)退出
					close(endDone)
                    return
				}
			}()
			// 監(jiān)聽(tīng)父協(xié)程狀態(tài)
			select {
			// 超時(shí)退出父協(xié)程,這里需要注意此時(shí)如果子協(xié)程已經(jīng)執(zhí)行并超時(shí),子協(xié)程會(huì)繼續(xù)執(zhí)行中直到關(guān)閉,這塊需要關(guān)注下。比如:查看數(shù)據(jù)確定數(shù)據(jù)是否已被修改等。
			case <-ctx.Done():
				fmt.Println("超時(shí)退出", i)
				cancel()
				return
			// 主動(dòng)關(guān)閉
			case <-endDone:
				fmt.Println("主動(dòng)退出", i)
				cancel()
				return
			}
		}(i)
	}
	//time.Sleep(8 * time.Second)
	time.Sleep(12 * time.Second)
	// 查看當(dāng)前還存在多少運(yùn)行中的goroutine
	fmt.Println("number of goroutines:", runtime.NumGoroutine())
}

2.go-zero實(shí)現(xiàn)方式

package main
import (
	"context"
	"fmt"
	"runtime/debug"
	"strings"
	"time"
)
var (
	// ErrCanceled是取消上下文時(shí)返回的錯(cuò)誤。
	ErrCanceled = context.Canceled
	// ErrTimeout是當(dāng)上下文的截止日期過(guò)去時(shí)返回的錯(cuò)誤。
	ErrTimeout = context.DeadlineExceeded
)
// DoOption定義了自定義DoWithTimeout調(diào)用的方法。
type DoOption func() context.Context
// DoWithTimeout運(yùn)行帶有超時(shí)控制的fn。
func DoWithTimeout(fn func() error, timeout time.Duration, opts ...DoOption) error {
	parentCtx := context.Background()
	for _, opt := range opts {
		parentCtx = opt()
	}
	ctx, cancel := context.WithTimeout(parentCtx, timeout)
	defer cancel()
	// 創(chuàng)建緩沖區(qū)大小為1的通道以避免goroutine泄漏
	done := make(chan error, 1)
	panicChan := make(chan interface{}, 1)
	go func() {
		defer func() {
			if p := recover(); p != nil {
				// 附加調(diào)用堆棧以避免在不同的goroutine中丟失
				panicChan <- fmt.Sprintf("%+v\n\n%s", p, strings.TrimSpace(string(debug.Stack())))
			}
		}()
		done <- fn()
	}()
	select {
	case p := <-panicChan:
		panic(p)
	case err := <-done:
		return err
	case <-ctx.Done():
		return ctx.Err()
	}
}
// WithContext使用給定的ctx自定義DoWithTimeout調(diào)用。
func WithContext(ctx context.Context) DoOption {
	return func() context.Context {
		return ctx
	}
}
func main() {
	ctx, cancel := context.WithCancel(context.Background())
	go func() {
		fmt.Println(1111)
		time.Sleep(time.Second * 5)
		fmt.Println(2222)
		cancel()
	}()
	err := DoWithTimeout(func() error {
		fmt.Println("aaaa")
		time.Sleep(10 * time.Second)
		fmt.Println("bbbb")
		return nil
	}, 3*time.Second, WithContext(ctx))
	fmt.Println(err)
	time.Sleep(15 * time.Second)
	//err := DoWithTimeout(func() error {
	//	fmt.Println(111)
	//	time.Sleep(time.Second * 3)
	//	fmt.Println(222)
	//	return nil
	//}, time.Second*2)
	//
	//fmt.Println(err)
	//time.Sleep(6 * time.Second)
	//
	//fmt.Println("number of goroutines:", runtime.NumGoroutine())
}
package fx
import (
	"context"
	"testing"
	"time"
	"github.com/stretchr/testify/assert"
)
func TestWithPanic(t *testing.T) {
	assert.Panics(t, func() {
		_ = DoWithTimeout(func() error {
			panic("hello")
		}, time.Millisecond*50)
	})
}
func TestWithTimeout(t *testing.T) {
	assert.Equal(t, ErrTimeout, DoWithTimeout(func() error {
		time.Sleep(time.Millisecond * 50)
		return nil
	}, time.Millisecond))
}
func TestWithoutTimeout(t *testing.T) {
	assert.Nil(t, DoWithTimeout(func() error {
		return nil
	}, time.Millisecond*50))
}
func TestWithCancel(t *testing.T) {
	ctx, cancel := context.WithCancel(context.Background())
	go func() {
		time.Sleep(time.Millisecond * 10)
		cancel()
	}()
	err := DoWithTimeout(func() error {
		time.Sleep(time.Minute)
		return nil
	}, time.Second, WithContext(ctx))
	assert.Equal(t, ErrCanceled, err)
}

參考文獻(xiàn):

 https://github.com/zeromicro/go-zero/blob/master/core/fx/timeout.go

 一文搞懂 Go 超時(shí)控制_51CTO博客_go 超時(shí)處理

到此這篇關(guān)于golang Goroutine超時(shí)控制的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)go Goroutine超時(shí)控制內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Go語(yǔ)言學(xué)習(xí)技巧之命名規(guī)范

    Go語(yǔ)言學(xué)習(xí)技巧之命名規(guī)范

    最近在學(xué)習(xí)go語(yǔ)言,發(fā)現(xiàn)了不少需要整理的知識(shí)點(diǎn),所以整理下分享出來(lái),下面這篇文章主要給大家介紹了關(guān)于Go語(yǔ)言學(xué)習(xí)技巧之命名規(guī)范的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面來(lái)一起看看吧。
    2017-12-12
  • Windows下安裝VScode 并使用及中文配置方法

    Windows下安裝VScode 并使用及中文配置方法

    這篇文章主要介紹了Windows下安裝VScode 并使用及中文配置的方法詳解,本文通過(guò)圖文并茂的形式給大家介紹,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-03-03
  • gin正確多次讀取http?request?body內(nèi)容實(shí)現(xiàn)詳解

    gin正確多次讀取http?request?body內(nèi)容實(shí)現(xiàn)詳解

    這篇文章主要為大家介紹了gin正確多次讀取http?request?body內(nèi)容實(shí)現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-01-01
  • Golang讀寫(xiě)二進(jìn)制文件方法總結(jié)

    Golang讀寫(xiě)二進(jìn)制文件方法總結(jié)

    使用?Golang?的?encoding/gob?包讀寫(xiě)二進(jìn)制文件非常方便,而且代碼量也非常少,本文就來(lái)通過(guò)兩個(gè)示例帶大家了解一下encoding/gob的具體用法吧
    2023-05-05
  • 詳解MongoDB?Go?Driver如何記錄日志

    詳解MongoDB?Go?Driver如何記錄日志

    這篇文章主要為大家介紹了MongoDB?Go?Driver如何記錄日志詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-08-08
  • Go語(yǔ)言錯(cuò)誤處理異常捕獲+異常拋出

    Go語(yǔ)言錯(cuò)誤處理異常捕獲+異常拋出

    這篇文章主要介紹了Go語(yǔ)言錯(cuò)誤處理異常捕獲和異常拋出,Go語(yǔ)言的作者認(rèn)為java等語(yǔ)言的錯(cuò)誤處理底層實(shí)現(xiàn)較為復(fù)雜,就實(shí)現(xiàn)了函數(shù)可以返回錯(cuò)誤類(lèi)型以及簡(jiǎn)單的異常捕獲,雖然簡(jiǎn)單但是也非常精妙,大大的提高了運(yùn)行效率,下文需要的朋友可以參考一下
    2022-02-02
  • golang如何判斷文件是否存在

    golang如何判斷文件是否存在

    判斷一個(gè)文件是否存在是一個(gè)相當(dāng)常見(jiàn)的需求,在golang中也有多種方案實(shí)現(xiàn)這一功能,下面就跟隨小編一起學(xué)習(xí)一下具體的實(shí)現(xiàn)方法吧
    2024-11-11
  • Go1.21新增slices包中函數(shù)的用法詳解

    Go1.21新增slices包中函數(shù)的用法詳解

    Go?1.21新增的?slices?包提供了很多和切片相關(guān)的函數(shù),可以用于任何類(lèi)型的切片,本文為大家整理了部分函數(shù)的具體用法,感興趣的小伙伴可以了解一下
    2023-08-08
  • Go語(yǔ)言中三個(gè)輸入函數(shù)(scanf,scan,scanln)的區(qū)別解析

    Go語(yǔ)言中三個(gè)輸入函數(shù)(scanf,scan,scanln)的區(qū)別解析

    本文詳細(xì)介紹了Go語(yǔ)言中三個(gè)輸入函數(shù)Scanf、Scan和Scanln的區(qū)別,包括用法、功能和輸入終止條件等,本文給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧
    2024-10-10
  • Go語(yǔ)言如何使用分布式鎖解決并發(fā)問(wèn)題

    Go語(yǔ)言如何使用分布式鎖解決并發(fā)問(wèn)題

    這篇文章主要為大家詳細(xì)介紹了Go 語(yǔ)言生態(tài)中基于 Redis 實(shí)現(xiàn)的分布式鎖庫(kù) redsync,并探討其使用方法和實(shí)現(xiàn)原理,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2025-03-03

最新評(píng)論