Timer in Go ' runtime

Source: Internet
Author: User
This is a creation in Article, where the information may have evolved or changed.

We always use the sleep () class function to suspend a thread for a while, and in the go language, we use sleep () to pause Goroutine. So how is the sleep of go language realistic? Of course, you look at the standard library in the time package inside the Sleep.go source code, you may feel that you do not understand, because the real implementation of the support sleep function is inside the runtime. It's not hard to think that the sleep function is based on a timer, so let's look at what the timer in runtime looks like.

The implementation of the timer is mainly in the Runtime/time.goc file.

Main data structures

struct  Timers{    Lock;    G       *timerproc;    bool    sleeping;    bool    rescheduling;    Note    waitnote;    Timer   **t;    int32   len;    int32   cap;};struct  Timer{    int32   i;      // heap index    // Timer wakes up at when, and then at when+period, ... (period > 0 only)    // each time calling f(now, arg) in the timer goroutine, so f must be    // a well-behaved function and not block.    int64   when;    int64   period;    FuncVal *fv;    Eface   arg;};

These two structures are defined in the Runtime.h file.

Calling sleep once is actually generating one and Timer then adding it to Timers the. It can be seen that timers is a collection of all the timer's. In addition to adding a timer to timers, you also remove the timed-out timer from timers. Therefore, timers uses the small top heap to maintain, the small top heap is commonly used to manage the timer structure, in some places also uses the red black tree.

Timers

    • There is one in the timers structure Lock , presumably to know that it is used to protect 添加/删除 the timer, is actually doing this thing.
    • timerprocThe pointer maintains a goroutine, and the main function of this goroutine is to check if the timer in the small top heap is timed out. Of course, the timeout is to delete the timer and perform the corresponding action of the timer.
    • tIt's obviously the heap that stores all the timer.

Omit several fields to be described below.

Timer

    • whenis when the timer expires.
    • fvand arg mount are the methods that need to be executed after the timer expires.

In this, the Go language timer model can be imagined. In fact, the implementation of all the timers are the same, all the same length.

Timerproc Goroutine

The above mentioned Timerproc maintenance is a goroutine, this goroutine do one thing--constantly loop check the heap, delete those timed out timer, and execute timer. The following concise code, look at a skeleton is enough to understand.

static voidtimerproc(void){    for(;;) {        for(;;) {            // 判断Timer是否超时            t = timers.t[0];            delta = t->when - now;            if(delta > 0)                break;            // TODO: 删除Timer, 代码被删除            // 这里的f调用就是执行Timer了            f(now, arg);        }        // 这个过程是,堆中没有任何Timer的时候,就把这个goroutine给挂起,不运行。        // 添加Timer的时候才会让它ready。        if(delta < 0) {            // No timers left - put goroutine to sleep.            timers.rescheduling = true;            runtime·park(runtime·unlock, &timers, "timer goroutine (idle)");            continue;        }        // 这里干的时候就让这个goroutine也sleep, 等待最近的Timer超时,再开始执行上面的循环检查。当然,这里的sleep不是用本文的定时器来实现的,而是futex锁实现。        // At least one timer pending.  Sleep until then.        timers.sleeping = true;        runtime·notetsleep(&timers.waitnote, delta);        }    }}

It is important to remember that this timerproc is done in a separate goroutine. The process of combing the above code:

    1. Determine if there is a timer in the heap? If no state is Timers rescheduling set to True, true means that Timerproc Goroutine is suspended and needs to be re-dispatched. This re-scheduling is the time to add a timer to come in, will be ready to this goroutine. Hang up here Goroutine is using the runtime Park () function.
    2. If a timer exists in the heap, take a timer from the top of the heap and determine if it is timed out. After the timeout, delete the timer and execute the method that was mounted in the timer. This step is to loop through the heap until there is no timer in the heap or a timer without a timeout.
    3. Before the timer in the heap expires, the goroutine will be in the sleep state, which is Timers set sleeping to True. This place is done through the runtime Notesleep () function, and its implementation is dependent on the Futex lock. Here, how long will the Goroutine sleep? It will sleep until the most recent timer expires and starts executing.

Maintenance timers Time-out goroutine all the things that are done with this, in addition to the heap maintenance, is goroutine dispatch.

Add a Timer

Another important process is how to complete the addition of a timer? Similarly, the code is reduced, preferably against the full source of the view.

static voidaddtimer(Timer *t){    if(timers.len >= timers.cap) {        // TODO 这里是堆没有剩余的空间了,需要分配一个更大的堆来完成添加Timer。    }    // 这里添加Timer到堆中.    t->i = timers.len++;    timers.t[t->i] = t;    siftup(t->i);    // 这个地方比较重要,这是发生在添加的Timer直接位于堆顶的时候,堆顶位置就代表最近的一个超时Timer.    if(t->i == 0) {        // siftup moved to top: new earliest deadline.        if(timers.sleeping) {            timers.sleeping = false;            runtime·notewakeup(&timers.waitnote);        }        if(timers.rescheduling) {            timers.rescheduling = false;            runtime·ready(timers.timerproc);        }    }}

From the code can see the newly added timer if it is a heap top, will check Timers the sleeping and rescheduling two states. As already mentioned above, these two States represent the state of Timeproc Goroutine, and if it is in sleeping, then wakeup it; If it's rescheduling, just ready it. The reason for this is to inform the wait goroutine--"there is a timer in the heap" or "heap top of the timer is easy to master", you hurry to check whether it timed out.

The process of adding a timer is simply too simple, and the key point is the final timers state check logic.

Implementation of Sleep ()

The above explains how the runtime timer works, so how does the go language implement sleep () on the basis of the timer?

After calling Time.sleep () in the Go program, it will enter runtime and execute the following code:

voidruntime·tsleep(int64 ns, int8 *reason){    Timer t;    if(ns <= 0)        return;    t.when = runtime·nanotime() + ns;    t.period = 0;    t.fv = &readyv;    t.arg.data = g;    runtime·lock(&timers);    addtimer(&t);    runtime·park(runtime·unlock, &timers, reason);}

Sleep originally created a timer, added to timers, and finally called Runtime Park () to suspend the current call to sleep () goroutine.

The point is, how do I wake up and continue to run after the Goroutine is suspended? This is where the timer fv and arg two fields are mounted to complete. Here, FV mounts &readyv , look at the definition of READYV:

static voidready(int64 now, Eface e){    USED(now);    runtime·ready(e.data);}static FuncVal readyv = {(void(*)(void))ready};

Readyv is actually pointing to the ready function, which will be executed when the timer expires and it will be ready to be suspended goroutine. t.arg.data = g;This line of code is to save the current goroutine.

The Sleep () implementation sums up three big strides:

    1. Create a timer to add to the timers
    2. Suspend current Goroutine
    3. Timer timed out ready current Goroutine

The Go language timer implementation is still relatively clear, there is no cumbersome logic. Compared to other places (such as Nginx) implementation, this may be more than the goroutine of the dispatch logic.

To see the realization of a thing, it is important to know why the author should do so. How can only be valuable if you understand why.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.