• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

go的协程

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

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\n", 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是否需要收缩.


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
Go后端主要做什么发布时间:2022-07-10
下一篇:
cannotdownload,$GOPATHnotset.Formoredetailssee:gohelpgopath发布时间:2022-07-10
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap