Go Language Scheduler

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

The scheduler is the assignment of goroutine to a worker thread to run
There are 3 types of objects involved:
G-goroutine
M-worker thread i.e. OS thread
P-processor, an abstract resource used to run go code, the maximum number cannot exceed gomaxprocs, you need to associate a m when running the go Code

Global Run Queue:

G *runtime·sched.runqhead;G *runtime·sched.runqtail;int runtime·sched.runqsize;

Primary member of the P structure: contains a local run queue

struct P{    uint32status;// one of Pidle/Prunning/...    uint32schedtick;// incremented on every scheduler call     M*m;// back-link to associated M (nil if idle)     // Queue of runnable goroutines.    uint32runqhead;    uint32runqtail;    G*runq[256];};

Schedule function Main part code

One round of Scheduler:find a runnable goroutine and execute it.//never returns.static voidschedule (void) {G *gp;     UInt32 tick;    ..... Top: ... gp = nil;    Check the global runnable queue once in a and to ensure fairness.    Otherwise Goroutines can completely occupy the local runqueue//by constantly respawning per other.    Tick = g->m->p->schedtick; This is a fancy-to-say tick%61==0,//It uses 2 MUL instructions instead of a single DIV and so are faster on mod    Ern processors. if (tick-((UInt64) tick*0x4325c53fu) >>36) *61 = = 0 && runtime sched.runqsize > 0) {Runtime Lock (&    Runtime Sched.lock);    GP = Globrunqget (g->m->p, 1);    Runtime unlock (&runtime sched.lock);    if (GP) resetspinning ();    } if (gp = = nil) {GP = Runqget (g->m->p);    if (GP && g->m->spinning) Runtime throw ("schedule:spinning with local work"); } if (gp = = nil) {GP = FindruNnable ();    Blocks until work is available resetspinning (); } execute (GP);}

In the case of a scheduler exceeding a certain interval, for the sake of fairness, the first is to get G from the global run queue
Get g from the local run queue
Wait for the new G to enter the run queue

Globrunqget gets G from the global run queue, and it also transfers a certain number of G to the local run queue of P.

Runqget get G from the local run queue, the implementation of the local run queue is unlocked:

// Get g from local runnable queue.// Executed only by the owner P.static G*runqget(P *p){    G *gp;    uint32 t, h;     for(;;) {    h = runtime·atomicload(&p->runqhead);  // load-acquire, synchronize with other consumers    t = p->runqtail;    if(t == h)    return nil;    gp = p->runq[h%nelem(p->runq)];    if(runtime·cas(&p->runqhead, h, h+1))  // cas-release, commits consume    return gp;    }}

Findrunnable blocking waiting for a running G

  • Check the local run queue
  • Check the global run queue
  • Poll Network in non-blocking mode
  • Check the local run queue of other p
  • If G is still not available in the system at the end, then poll the network in blocking mode

    Finds a runnable goroutine to execute.
    Tries to steal from the other P ' s, the get G from global queue, poll network.
    Static G
    Findrunnable (void)
    {
    G
    GP;
    P *p;
    Int32 i;

    Top
    if (runtime sched.gcwaiting) {
    GCSTOPM ();
    Goto top;
    }
    if (runtime fingwait && runtime Fingwake && (gp = Runtime wakefing ()) = nil)
    Runtime ready (GP);
    Local RUNQ
    GP = Runqget (g->m->p);
    if (GP)
    return GP;
    Global RUNQ
    if (runtime Sched.runqsize) {
    Runtime Lock (&runtime Sched.lock);
    GP = Globrunqget (g->m->p, 0);
    Runtime unlock (&runtime sched.lock);
    if (GP)
    return GP;
    }
    Poll Network
    GP = Runtime Netpoll (false); Non-blocking
    if (GP) {
    Injectglist (Gp->schedlink);
    Runtime Casgstatus (GP, gwaiting, grunnable);
    return GP;
    }
    If number of spinning M ' s >= number of busy P ' s, block.
    This is necessary to prevent excessive CPU consumption
    When Gomaxprocs>>1 and the program parallelism are low.
    if (!g->m->spinning && 2 * Runtime Atomicload (&runtime sched.nmspinning) >= Runtime Gomaxprocs- Runtime Atomicload (&runtime Sched.npidle))//Todo:fast Atomic
    Goto stop;
    if (!g->m->spinning) {
    G->m->spinning = true;
    Runtime Xadd (&runtime sched.nmspinning, 1);
    }
    Random steal from other P ' s
    for (i = 0; i < 2*runtime gomaxprocs; i++) {
    if (runtime sched.gcwaiting)
    Goto top;
    p = Runtime Allp[runtime fastrand1 ()%runtime Gomaxprocs];
    if (p = = g->m->p)
    GP = Runqget (p);
    Else
    GP = Runqsteal (g->m->p, p);
    if (GP)
    return GP;
    }
    Stop
    Return P and block
    Runtime Lock (&runtime Sched.lock);
    if (runtime sched.gcwaiting) {
    Runtime unlock (&runtime sched.lock);
    Goto top;
    }
    if (runtime Sched.runqsize) {
    GP = Globrunqget (g->m->p, 0);
    Runtime unlock (&runtime sched.lock);
    return GP;
    }
    p = releasep ();
    Pidleput (P);
    Runtime unlock (&runtime sched.lock);
    if (g->m->spinning) {
    G->m->spinning = false;
    Runtime Xadd (&runtime sched.nmspinning,-1);
    }
    Check all runqueues once again
    for (i = 0; i < runtime gomaxprocs; i++) {
    p = Runtime Allp[i];
    if (P && p->runqhead! = p->runqtail) {
    Runtime Lock (&runtime Sched.lock);
    p = pidleget ();
    Runtime unlock (&runtime sched.lock);
    if (p) {
    Acquirep (P);
    Goto top;
    }
    Break
    }
    }
    Poll Network
    if (Runtime xchg64 (&runtime sched.lastpoll, 0)! = 0) {
    if (g->m->p)
    Runtime throw ("Findrunnable:netpoll with P");
    if (g->m->spinning)
    Runtime throw ("Findrunnable:netpoll with Spinning");
    GP = Runtime Netpoll (true); Block until new work is available
    Runtime Atomicstore64 (&runtime Sched.lastpoll, Runtime Nanotime ());
    if (GP) {
    Runtime Lock (&runtime Sched.lock);
    p = pidleget ();
    Runtime unlock (&runtime sched.lock);
    if (p) {
    Acquirep (P);
    Injectglist (Gp->schedlink);
    Runtime Casgstatus (GP, gwaiting, grunnable);
    return GP;
    }
    Injectglist (GP);
    }
    }
    STOPM ();
    Goto top;
    }

Related Article

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.