Go语言并发之道学习十三 治愈异常的goroutine

治愈异常的goroutine

package main

import (
	"log"
	"time"
	"os"
)

/*
治愈异常的goroutine:
在长期运行的后台程序中,经常会有一些长时间运行的goroutine。
这些goroutine 经常处于阻塞状态,等待数据以某种方式到达,然后唤醒它们,进行一些处理,再返回一些数据。
如果没有外部干预,一个goroutine 很容易进入一个不正常的状态,并且无法恢复。
我们需要建立一个机制来监控你的goroutine 是否处于健康的状态是很有用的,
当他们变得异常时,就可以尽快重启。

我们将这种重启goroutine的过程称为治愈。

为了治愈goroutine ,我们需要使用心跳模式来检查我们正在监控的goroutine 是否活跃。
心跳的类型取决于你想要监控的内容,但是如果你的goroutine 有可能会产生活锁,确保心跳包含某些信息,表明该goroutine 在正常的工作而不仅仅是活着。
我们把监控goroutine 的健康这段逻辑称为管理员,它监视一个管理区的goroutine,
如果有goroutine 变得不健康,管理员将负责重新启动这个管理区的goroutine 。

*/

func main() {
	log.Println("testhealing")
	testhealing()
	log.Println()
	log.Println("testhealing2")
	testhealink2()
}


func testhealing()  {
	var or func(channels ...<-chan interface{}) <-chan interface{}
	or = func(channels ...<-chan interface{}) <-chan interface{}{
		switch len(channels) {
		case 0:
			return nil
		case 1:
			return channels[0]
		}

		orDone := make(chan interface{})
		go func() {
			defer close(orDone)

			switch len(channels) {
			case 2:
				select {
				case <-channels[0]:
				case <-channels[1]:
				}
			default:
				select{
				case <-channels[0]:
				case <-channels[1]:
				case <-channels[2]:
				case <-or(append(channels[3:],orDone)...):
				}
			}
		}()
		return orDone
	}


	type startGoroutineFn func(
		done <-chan interface{},
		pulseInterval time.Duration,
		)(heartbeat <-chan interface{})
	
	newSteward := func(
		timeout time.Duration,
		startGoroutine startGoroutineFn,
		) startGoroutineFn {
			return func(
				done <-chan interface{},
				pulseInterval time.Duration,
				) (<-chan interface{}) {
				heartbeat := make(chan interface{})
				go func() {
					defer close(heartbeat)

					var wardDone chan interface{}
					var wardHeartbeat <-chan interface{}
					startWard := func() {
						wardDone = make(chan interface{})
						wardHeartbeat = startGoroutine(or(wardDone,done),timeout/2)
					}
					startWard()
					pulse := time.Tick(pulseInterval)

					monitorLoop:
						for{
							timeoutSignal := time.After(timeout)
							for {
								select {
								case <-pulse:
									select {
									case heartbeat<- struct {}{}:
									default:
									}
								case <-wardHeartbeat:
									continue monitorLoop
								case <-timeoutSignal:
									log.Println("steward:ward unhealthy;restarting")
									close(wardDone)
									startWard()
									continue monitorLoop
								case <-done:
									return
								}
							}
						}
				}()
				return heartbeat
			}
		
	}

	/*
	· pulseInterval time.Duration,
	   )(heartbeat <-chan interface{})
	在这里,我们定义一个可以监控和重启的goroutine 的信号,
	我们看到了熟悉的channel ,以及来自心跳模式的pulseInterval 和heartbeat

	·timeout time.Duration,
	  startGoroutine startGoroutineFn,
	  ) startGoroutineFn {
	在这,我们看到一个管理员监控goroutine 需要timeout 变量,
	还有一个函数startGoroutine 来启动他监控的goroutine
	管理员本身会返回一个startGoroutineFn ,表示管理员本身也是可监控的

	·startWard := func() {
	在这里,我们定义了一个闭包,他实现了一个统一的startWard 方法来启动我们正在监视的goroutine

	·wardDone = make(chan interface{})
	这是我们创建的一个新的channel ,如果我们需要发出一个停止的信号,就会通过他传入goroutine 中

	·wardHeartbeat = startGoroutine(or(wardDone,done),timeout/2)
	在这,我们启动将要监控的goroutine ,如果管理员被停止了,或者管理员想要停止goroutine
	我们希望这些信息都能传递给管理区里的goroutine ,所有我们把两个done channel 用逻辑 or 包装一下。
	我们设定心跳间隔时间是超时时间的一半

	·timeoutSignal := time.After(timeout)
	  for {
	这里我们的内部循环,他确保管理员可以发出自己的心跳

	·case <-wardHeartbeat:
	在这,如果我们收到goroutine 的心跳,将继续执行监控的循环

	·case <-timeoutSignal:
	这里如果我们在暂停期间没有收到管理区里goroutine 的心跳,
	我们会要求管理区里的goroutine 停下来,并启动一个新的goroutine ,然后我们继续监控

	*/

	log.SetOutput(os.Stdout)
	log.SetFlags(log.Ltime|log.LUTC)

	doWork := func(
		done <-chan interface{},
		_ time.Duration,
		) <-chan interface{}{
			log.Println("ward:hello, i,m irresponsible!")
			go func() {
				<-done
				log.Println("ward:i am halting.")
			}()
			return nil
	}
		doWorkWithSteward := newSteward(1*time.Second,doWork)

		done := make(chan interface{})
		time.AfterFunc(5*time.Second, func() {
			log.Println("main:halting steward and ward.")
			close(done)
		})

		for range doWorkWithSteward(done,2*time.Second){

		}
		log.Println("Done")

		/*
		·go func() {
		  <-done
		在这里,我们看到这个goroutine 没有做任何事情,只是等待被取消,他也没有发出任何心跳

		·doWorkWithSteward := newSteward(4*time.Second,doWork)
		这里创建了一个函数,为goroutine doWork 创建一个管理员,我们设置doWork 的超时时间为4秒

		·time.AfterFunc(9*time.Second, func() {
		在这我们设置9秒后停止管理员和goroutine ,这样我们的测试就会结束。

		·for range doWorkWithSteward(done,4*time.Second){
		最后,我们启动管理员并在其心跳范围内防止我们的测试停止

		*/

}

func testhealink2(){
	var or func(channels ...<-chan interface{}) <-chan interface{}
	or = func(channels ...<-chan interface{}) <-chan interface{}{
		switch len(channels) {
		case 0:
			return nil
		case 1:
			return channels[0]
		}

		orDone := make(chan interface{})
		go func() {
			defer close(orDone)

			switch len(channels) {
			case 2:
				select {
				case <-channels[0]:
				case <-channels[1]:
				}
			default:
				select{
				case <-channels[0]:
				case <-channels[1]:
				case <-channels[2]:
				case <-or(append(channels[3:],orDone)...):
				}
			}
		}()
		return orDone
	}

	orDone := func(
		done <-chan interface{},
		valueStream <-chan interface{},
	)<-chan interface{}{
		doneStream := make(chan interface{})
		go func() {
			defer close(doneStream)
			for{
				select {
				case <-done:
					return
				case val,ok := <-valueStream:
					if ok == false{
						return
					}
					doneStream<-val
				}
			}
		}()
		return doneStream
	}
	//桥接channel
	bridge := func(
		done <-chan interface{},
		chanStream <-chan <-chan interface{},
	)<-chan interface{}{
		valueStream := make(chan interface{})
		go func() {
			defer close(valueStream)
			for{
				var stream <-chan interface{}
				select{
				case maybeStream,ok := <-chanStream:
					if ok == false{
						return
					}
					stream = maybeStream
				case <-done:
					return
				}
				for val := range orDone(done,stream){
					select{
					case <-done:
					case valueStream <-val:
					}
				}
			}
		}()
		return valueStream
	}
	take := func(
		done <-chan interface{},
		intStream <-chan interface{},
		num int,
		) <-chan interface {}{
			takeStream := make(chan interface{})
			go func() {
				defer close(takeStream)
				for i :=0;i

 

你可能感兴趣的:(go)