This is a creation in Article, where the information may have evolved or changed.
I recently learned to go, in order to gain insight into go, so plan to use go to implement a high concurrency, IO-intensive operation of the ETL program. Gossip not much to say, today completed the ETL of the most basic elements, timers.
First understand that go in the time.ticker is not suitable for high-precision timers, because the ETL task cycle is set to 1 minutes, so there is no need for high-precision timers (for high-precision timers, on-line to see someone using the time wheel to achieve timewheel, I also saw the implementation, and also according to their ideas to achieve a version, omitted here).
Closed type: Timeticker, use the sample code as follows:
Func Main () {
var tt *timeticker. Timeticker = Timeticker. New (3*time. Second)//Create a timer that performs a task for 3 seconds
E: = TT. AddJob (Job, true)//Add a task to this timer to return a pointer to this task (this indicator is used for subsequent delete tasks)
Go TT. Start ()//Open a co-process to allow this timer to perform the task alone
Time. Sleep (6*time. Second)
The main thread sleeps 6 seconds and then adds a task queue to the timer, and then performs two tasks per cycle
Tt. AddJob (Test_job, True)
Time. Sleep (10*time. Second)
Tt. Removetask (e)//main thread after 10 seconds of sleep, the first job is cleared, and the task queue has only one task left.
Time. Sleep (10*time. Second)
Tt. Stop ()//stops this timer and will later notice that the timer is no longer executing
Time. Sleep (5*time. Second)//sleep five seconds after exiting
}
Func test_job (... interface{}) {
Fmt. Print ("Test_job is call ...")
Fmt. Println (time. Now ())
}
Func Job (... interface{}) {
Fmt. Print ("Job is call ...")
Fmt. Println (time. Now ())
}
Program execution Results:
Job is call ... 2018-04-11 22:21:42.0179853 +0800 CST m=+0.005000301
Job is call ... 2018-04-11 22:21:45.0181569 +0800 CST m=+3.005171901
Test_job are call ... 2018-04-11 22:21:48.0183285 +0800 CST m=+6.005343501
Job is call ... 2018-04-11 22:21:48.0183285 +0800 CST m=+6.005343501
Job is call ... 2018-04-11 22:21:51.0185001 +0800 CST m=+9.005515101
Test_job are call ... 2018-04-11 22:21:51.0185001 +0800 CST m=+9.005515101
Test_job are call ... 2018-04-11 22:21:54.0186717 +0800 CST m=+12.005686701
Job is call ... 2018-04-11 22:21:54.0186717 +0800 CST m=+12.005686701
Test_job are call ... 2018-04-11 22:21:57.0188433 +0800 CST m=+15.005858301
Job is call ... 2018-04-11 22:21:57.0188433 +0800 CST m=+15.005858301
Test_job are call ... 2018-04-11 22:22:00.0180149 +0800 CST m=+18.005029901
Test_job are call ... 2018-04-11 22:22:03.0181865 +0800 CST m=+21.005201501
Test_job are call ... 2018-04-11 22:22:06.0183581 +0800 CST m=+24.005373101
From the above operating results can be seen, this timer to the second level is accurate, but the time accuracy is small will be biased, this is the beginning is not suitable for high-precision timers. The comments in the example code above are clear, and the code for the encapsulated timer is presented below (specially annotated to make it easier for the students to understand):
Code begin********************************
Package Timeticker
Import (
"FMT"
"Time"
"Reflect"
"Container/list"
)
Type Task struct {
Interval time. Duration//The current task is delayed for a long time after execution
Job func (... interface{})//callback function (the specific execution method of the task)
iscycle BOOL//Whether the task executes only once (true, once executed, it is purged from the execution queue
}
Timer type
Type Timeticker struct {
Interval time. Duration//Timer interval How long does it take to execute one time
Ticker *time. Ticker
Taskqueue *list. List
Closechan chan bool//Enter a true value into this channel to turn off this timer
}
Func New (interval time. Duration) *timeticker {
If interval <= 0 {
return Nil
}
TT: = &timeticker {
Interval:interval,
Taskqueue:list. New (),
Closechan:make (chan bool),
}
Return TT
}
Adding tasks to the task queue of the timer
Parameter: task--added task
iscycle--whether the loop executes, true, remains in the task queue after each execution, false, and is cleared after execution
Consider ways to add a set of tasks
Func (TT *timeticker) addtask (Task task, iscycle bool) {
Tt.taskQueue.PushBack (Task)
}
Func (TT *timeticker) addtasklist (Task task, iscycle bool) {
}
Add an execution task parameter: job--Specific execution function
iscycle--whether to loop execution, true: Loop execution, execute once per cycle, false: Execute only once, then clear from task queue
Func (TT *timeticker) addjob (Job func (... interface{}), iscycle bool) *list. Element {
Task: = &task {
interval:0,
Job:job,
Iscycle:iscycle,
}
E: = Tt.taskQueue.PushBack (Task)
Return E
}
Func (TT *timeticker) removetask (e *list. Element) {
Tt.taskQueue.Remove (e)
Fmt. Println (Tt.taskQueue.Len ())
}
Func (TT *timeticker) Stop () {
Tt.ticker.Stop ()
Tt.closechan <-True
}
Start the timer, if the parameter is not transmitted immediately start, otherwise delay time after the start
Func (TT *timeticker) Start (Delay ... time). Duration) {
If Len (delay) > 0 {//delay delay[0] time to start
} else {//start now
Tt.ticker = time. Newticker (Tt.interval)
Tt.executetaskqueue ()
for {
Select {
Case <-TT.TICKER.C:
Tt.executetaskqueue ()
Case <-Tt.closechan:
Return
}
}
}
}
Func (TT *timeticker) Executetaskqueue () {
If tt.taskQueue.Len () = = 0 {
Fmt. PRINTLN ("Task queue is empty, no executable task ...")
Return
}
For iter: = Tt.taskQueue.Front (); Iter! = Nil; ITER = iter. Next () {
T: = iter. Value
Task,ok: = T. (*task)
If OK {
Go Task.job ()
If!task.iscycle {
Iter_tmp: = iter
ITER = iter. Prev ()
Tt.taskQueue.Remove (ITER_TMP)
If iter = = Nil {
Return
}
}
}
}
}
Set the time-out mechanism, when this function is set, the timer starts from the task start time,
If the task in the task queue is still not completed after this time is reached, the remaining tasks are aborted and a warning is issued
Func (TT *timeticker) SetTimeOut (settime time. Duration) {
}
Code end********************************
Most of the functions are commented in detail before they can be read easily. There are some well-designed functions are not implemented, but the main function has come out, does not affect the use, and the most important reason is that the ETL does not have these (not implemented functions) of the requirements of the function, then stole a Lai.
338 Reads ∙1 likes