go中使用cmd與crontab

一、go中使用cmd

/bin/bash -c “ls -l”

cmd->golang->pipe

pipe()創建2個文件描述符,fd[0]可讀,fd[1]可寫
fork() 創建子進程 fd[1]被繼承到子進程
dup2() 重定向子進程 stdout/stderr到fd[1]
exec() 在當前進程內,加載並執行二進制程序

例子1

模擬一下cmd調用

package main

import (
	"fmt"
	"os/exec"
)

func main()  {
	var(
		cmd *exec.Cmd
		output []byte
		err error
	)
	//cmd = exec.Command("/bin/bash","-c","cd /tmp;ls -l")
	cmd = exec.Command("/bin/bash","-c","sleep 5;echo baidu.com")

	if output,err = cmd.CombinedOutput();err!=nil{
		fmt.Println(err)
		return
	}
	fmt.Println(string(output))
}


例子2

模擬調用cmd時,殺死bash進程

package main

import (
	"context"
	"fmt"
	"os/exec"
	"time"
)
type result struct {
	err error
	output []byte
}
func main()  {
	var(
		ctx context.Context
		cancelFunc context.CancelFunc
		cmd *exec.Cmd
		resultChan chan *result
		res *result
	)
	//創建一個結果對列
	resultChan = make(chan *result,1000)
	//context chan byte
	//cnacelFnc: close(chan byte)
	ctx,cancelFunc  = context.WithCancel(context.TODO())
	go func() {
		var(
			output [] byte
			err error
		)
		//select {case <-ctx.Done}
		// 監聽到 select中有<-ctx.Done 就殺掉當前的命令 pid , kill bash
		cmd = exec.CommandContext(ctx,"/bin/bash","-c","sleep 2;echo hello;")

		//執行任務,捕獲輸出
		output,err = cmd.CombinedOutput()
		//任務輸出結果 傳給main協程
		resultChan <- &result{
			err:    err,
			output: output,
		}
	}()

	time.Sleep(time.Second*1) //這裏1秒後就要將content關閉,所以bash進程會被殺死
	cancelFunc()
	res = <-resultChan

	fmt.Println(res.err,string(res.output))
}

二、go中使用cron

Cron基本格式

shell命令
*/5 * * * * echo hello >/tmp/x.log
1-5 * * * * echo /usr/bin/python /data/x.py
0 10,22 * * * echo hello

go開源Cronexpr庫
Parse() 解析與校驗Cron表達式
Next() 根據當前時間,計算下一次調度時間

例子1

模擬一下cron調用

package main

import (
	"fmt"
	"github.com/gorhill/cronexpr"
	"time"
)

func main()  {
	var(
		expr *cronexpr.Expression
		err error
		now time.Time
		nextTime time.Time
	)
	if expr,err = cronexpr.Parse("*/5 * * * * * *");err!=nil{
		fmt.Println(err)
		return
	}

	now = time.Now()
	//下次調度時間
	nextTime = expr.Next(now)
	//多長時間後運行
	time.AfterFunc(nextTime.Sub(now), func() {
		fmt.Println("被調度了:",nextTime)
	})

	time.Sleep(time.Second*5)

}

執行結果

被調度了: 2020-02-05 17:19:25 +0800 CST

例子2

模擬多個cron調用

package main

import (
	"fmt"
	"github.com/gorhill/cronexpr"
	"time"
)

type CronJob struct {
	expr     *cronexpr.Expression
	nextTime time.Time
}

func main() {

	var (
		cronJob       *CronJob
		expr          *cronexpr.Expression //表達式
		now           time.Time
		scheduleTable map[string]*CronJob //任務表
	)
	scheduleTable = make(map[string]*CronJob)
	//當前時間
	now = time.Now()
	//Cron表達式
	expr = cronexpr.MustParse("*/5 * * * * * *")
	cronJob = &CronJob{
		expr:     expr,
		nextTime: expr.Next(now),
	}
	//任務註冊到任務表中
	scheduleTable["job1"] = cronJob

	expr = cronexpr.MustParse("*/5 * * * * * *")
	cronJob = &CronJob{
		expr:     expr,
		nextTime: expr.Next(now),
	}
	//任務註冊到任務表中
	scheduleTable["job2"] = cronJob

	// 需要有1個調度協程,它定時檢查所有的Cron任務,誰過期就執行誰
	go func() {
		var (
			jobName string
			cronJob *CronJob
			now     time.Time
		)
		//定時看任務表
		for {
			now = time.Now()
			for jobName, cronJob = range scheduleTable {
				if cronJob.nextTime.Before(now) || cronJob.nextTime.Equal(now) {
					//啓動一個協程,執行這個任務
					go func(jobName string) {
						fmt.Println("執行:", jobName)
					}(jobName)

					//計算下一次執行時間
					cronJob.nextTime = cronJob.expr.Next(now)
					fmt.Println(jobName, "下次執行時間:", cronJob.nextTime)
				}
			}

			//這裏模擬一下休眠
			select {
			case <-time.NewTimer(time.Millisecond*100).C: //100毫秒可讀,返回

			}
		}
	}()

	time.Sleep(time.Second*100)
}

執行結果

執行: job1
job1 下次執行時間: 2020-02-05 17:08:55 +0800 CST
job2 下次執行時間: 2020-02-05 17:08:55 +0800 CST
執行: job2
執行: job1
job1 下次執行時間: 2020-02-05 17:09:00 +0800 CST
job2 下次執行時間: 2020-02-05 17:09:00 +0800 CST


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章