一、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