zoukankan      html  css  js  c++  java
  • go的协程

    goroutine代表一个调度单位

    创建一个G的过程:

    // Create a new g running fn with narg bytes of arguments starting
    // at argp and returning nret bytes of results.  callerpc is the
    // address of the go statement that created this.  The new g is put
    // on the queue of g's waiting to run.
    G*
    runtime·newproc1(FuncVal *fn, byte *argp, int32 narg, int32 nret, void *callerpc)
    {
        byte *sp;
        G *newg;
        P *p;
        int32 siz;
     
        .......
        
        p = g->m->p;
        if((newg = gfget(p)) == nil) {
        	newg = runtime·malg(StackMin);
        	runtime·casgstatus(newg, Gidle, Gdead);
        	runtime·allgadd(newg); // publishes with a g->status of Gdead so GC scanner doesn't look at uninitialized stack.
        }
        if(newg->stack.hi == 0)
        	runtime·throw("newproc1: newg missing stack");
     
        if(runtime·readgstatus(newg) != Gdead) 
        	runtime·throw("newproc1: new g is not Gdead");
     
        sp = (byte*)newg->stack.hi;
        sp -= 4*sizeof(uintreg); // extra space in case of reads slightly beyond frame
        sp -= siz;
        runtime·memmove(sp, argp, narg);
        if(thechar == '5') {
        	// caller's LR
        	sp -= sizeof(void*);
        	*(void**)sp = nil;
        }
     
        runtime·memclr((byte*)&newg->sched, sizeof newg->sched);
        newg->sched.sp = (uintptr)sp;
        newg->sched.pc = (uintptr)runtime·goexit + PCQuantum; // +PCQuantum so that previous instruction is in same function
        newg->sched.g = newg;
        runtime·gostartcallfn(&newg->sched, fn);
        newg->gopc = (uintptr)callerpc;
        runtime·casgstatus(newg, Gdead, Grunnable);
        
        ......
        
        runqput(p, newg);
     
        if(runtime·atomicload(&runtime·sched.npidle) != 0 && runtime·atomicload(&runtime·sched.nmspinning) == 0 && fn->fn != runtime·main)  // TODO: fast atomic
        	wakep();
        g->m->locks--;
        if(g->m->locks == 0 && g->preempt)  // restore the preemption request in case we've cleared it in newstack
        	g->stackguard0 = StackPreempt;
        return newg;
    }
    
    • 从gfree list获取空闲的G
    • 分配新的G和相应的stack
    • 初始化G中的成员
    • 将G放入P的运行队列中等待调度器来执行
    • 唤醒空闲的P来运行新的G

    G的终止:

    // runtime·goexit continuation on g0.
    static void
    goexit0(G *gp)
    {
        runtime·casgstatus(gp, Grunning, Gdead);
        gp->m = nil;
        gp->lockedm = nil;
        g->m->lockedg = nil;
        gp->paniconfault = 0;
        gp->defer = nil; // should be true already but just in case.
        gp->panic = nil; // non-nil for Goexit during panic. points at stack-allocated data.
        gp->writebuf.array = nil;
        gp->writebuf.len = 0;
        gp->writebuf.cap = 0;
        gp->waitreason.str = nil;
        gp->waitreason.len = 0;
        gp->param = nil;
     
        dropg();
     
        if(g->m->locked & ~LockExternal) {
        	runtime·printf("invalid m->locked = %d
    ", g->m->locked);
        	runtime·throw("internal lockOSThread error");
        }	
        g->m->locked = 0;
        gfput(g->m->p, gp);
        schedule();
    }
    
    • 清空G的成员
    • 从M中分离G
    • 将G放入gfree list中
    • 调度执行其它的G

    goroutine的stack

    普通的G的初始stack大小为2048,在每个函数被调用之前,都会检查stack是否会越界,如果会越界,则首先要增加G的stack.
    在GC的过程中会检查G的stack是否需要收缩.

  • 相关阅读:
    laravel常用函数大全Helper
    laravel查询语句指定索引(mysql强制索引)
    laravel-admin后台系统开发
    ES搜索引擎详解
    怎么查看当前的git分支是基于哪个分支创建的
    laravel中使用offsetSet
    laragon安装新的php版本
    Laravel collect妙用
    composer install file could not be downloaded (HTTP/1.1 405 Not Allowed)
    garphql
  • 原文地址:https://www.cnblogs.com/richmonkey/p/4509663.html
Copyright © 2011-2022 走看看