Go言语Context运行全攻略-异步编程利器 (go言语判断常量)
概述
在Go言语中,Context(高低文)是一个十分关键的概念,特意是在处置恳求时。
准许在恳求的整个生命周期内传递数据、控制恳求的敞开、处置超时等。
本文将引见Go言语中Context的经常使用,协助更好地理解与处置恳求的传递与控制。
关键内容包括
Context基础
Context创立与传递
Context的超时与敞开
Context的链式操作
Context在并发中的运行
Context的运行场景
最佳通常与留意事项
1.Context基础
在Go言语中,context.Context接口定义了一个恳求的高低文。
它蕴含了恳求的截止期间、敞开信号和恳求的数据。
经常使用Context可以在恳求之间有效地传递数据,同时也可以控制恳求的生命周期。
typeContextinterface{Deadline()(deadlinetime.Time,okbool)Done()<-chanstruct{}Err()errorValue(keyinterface{})interface{}}
Context接口蕴含了四个方法:Deadline()前往Context的截止期间
Done()前往一个通道,它会在Context被敞开或超时时封锁
Err()前往Context的失误消息,Value(key)前往Context中与key关联的值。
2.Context创立与传递
2.1创立和传递Context
packagemnimport("context""fmt""time")funcmain(){//创立一个根ContextrootContext:=context.Background()//创立一个带有超时期间的Context,这里设置超时期间为2秒ctx,cancel:=context.WithTimeout(rootContext,2*time.Second)defercancel()//在新的goroutine中口头义务gofunc(ctxcontext.Context){select{case<-time.After(3*time.Second):fmt.Println("义务成功")case<-ctx.Done():fmt.Println("义务敞开或超时")}}(ctx)//期待一段期间,模拟程序运转time.Sleep(5*time.Second)}
在这个例子中,创立了一个带有2秒超时期间的Context,并在一个新的goroutine中口头一个义务。
在主goroutine中,期待了5秒,因此义务在超时之前成功,所以会输入"义务成功"。
2.2经常使用WithValue传递数据
packagemainimport("context""fmt")typekeystringfuncmain(){//创立一个根ContextrootContext:=context.Background()//经常使用WithValue传递数据ctx:=context.WithValue(rootContext,key("userID"),123)//在子函数中失掉传递的数据getUserID(ctx)}funcgetUserID(ctxcontext.Context){//从Context中失掉数据ifuserID,ok:=ctx.Value(key("userID")).(int);ok{fmt.Println("UserID:",userID)}else{fmt.Println("UserID不存在")}}
在这个示例中,经常使用WithValue方法在Context中传递了一个userID的值,并在getUserID函数中成功失掉并打印了这个值。
3.Context的超时与敞开
3.1设置恳求超时期间
packagemainimport("context""fmt""time")funcmain(){//创立一个根ContextrootContext:=context.Background()//创立一个超时期间为2秒的ContexttimeoutCtx,_:=context.WithTimeout(rootContext,2*time.Second)//创立一个手动敞开的ContextcancelCtx,cancel:=context.WithCancel(rootContext)defercancel()//在新的goroutine中口头义务gofunc(ctxcontext.Context){select{case<-time.After(3*time.Second):fmt.Println("义务成功")case<-ctx.Done():fmt.Println("义务敞开或超时")}}(timeoutCtx)//在另一个goroutine中口头义务gofunc(ctxcontext.Context){select{case<-time.After(1*time.Second):fmt.Println("另一个义务成功")case<-ctx.Done():fmt.Println("另一个义务敞开")}}(cancelCtx)//期待一段期间,模拟程序运转time.Sleep(5*time.Second)}
在下面例子中,用WithTimeout方法创立了一个带有2秒超时期间的Context。
在义务的goroutine中,用select语句监听了超时和Context的敞开两个事情,以便及时照应。
3.2处置恳求敞开
packagemainimport("context""fmt""time")funcmain(){//创立一个根ContextrootContext:=context.Background()//创立一个可以手动敞开的Contextctx,cancel:=context.WithCancel(rootContext)defercancel()//在新的goroutine中口头义务gofunc(ctxcontext.Context){select{case<-time.After(3*time.Second):fmt.Println("义务成功")case<-ctx.Done():fmt.Println("义务敞开")}}(ctx)//期待一段期间,手动敞开义务time.Sleep(2*time.Second)cancel()//期待一段期间,模拟程序运转time.Sleep(1*time.Second)}
在下面例子中,经常使用WithCancel方法创立了一个可以手动敞开的Context。
在主函数中,期待了2秒后,手动调用cancel函数敞开了义务。
这时,在义务的goroutine中,ctx.Done()会接纳到敞开信号,从而分开义务。
4.Context的链式操作
在实践运行中,或许须要将多个Context串联起来经常使用。
Go言语的Context提供了WithCancel、WithDeadline、WithTimeout等方法。
可以用这些方法成功多个Context的协同上班。
packagemainimport("context""fmt""time")funcmain(){//创立一个根ContextrootContext:=context.Background()//创立一个超时期间为2秒的ContexttimeoutCtx,_:=context.WithTimeout(rootContext,2*time.Second)//创立一个手动敞开的ContextcancelCtx,cancel:=context.WithCancel(rootContext)defercancel()//在新的goroutine中口头义务gofunc(ctxcontext.Context){select{case<-time.After(3*time.Second):fmt.Println("义务成功")case<-ctx.Done():fmt.Println("义务敞开或超时")}}(timeoutCtx)//在另一个goroutine中口头义务gofunc(ctxcontext.Context){select{case<-time.After(1*time.Second):fmt.Println("另一个义务成功")case<-ctx.Done():fmt.Println("另一个义务敞开")}}(cancelCtx)//期待一段期间,模拟程序运转time.Sleep(5*time.Second)}
在示例中,创立了一个带有2秒超时期间的Context和一个可以手动敞开的Context,而后区分传递给两个不同的义务。
在主函数中,期待了5秒,超时期间为2秒,因此第一个义务会因超时而敞开,第二个义务则会在1秒后成功。
5.Context在并发中的运行
5.1经常使用Context控制多个协程
packagemainimport("context""fmt""sync""time")funcmain(){//创立一个根ContextrootContext:=context.Background()//创立一个可以手动敞开的Contextctx,cancel:=context.WithCancel(rootContext)defercancel()//经常使用WaitGroup期待一切义务成功varwgsync.WaitGroup//启动多个协程口头义务fori:=0;i<5;i++{wg.Add(1)gofunc(idint){deferwg.Done()select{case<-time.After(time.Duration(id)*time.Second):fmt.Println("义务",id,"成功")case<-ctx.Done():fmt.Println("义务",id,"敞开")}}(i)}//期待一段期间,然先手动敞开义务time.Sleep(2*time.Second)cancel()//期待一切义务成功wg.Wait()}
在下面例子中,创立了一个可以手动敞开的Context,并经常使用sync.WaitGroup期待一切义务成功。
在for循环中,启动了5个协程,每个协程会期待一段期间后输入义务成功消息。
在主函数中,程序期待了2秒后,手动调用cancel函数敞开了义务,协程会接纳到敞开信号并分开。
5.2防止Context滥用
在经常使用Context时,要防止将Context放在结构体中。
由于Context应该作为函数参数传递,而不应该被放在结构体中启动传递。
Context应该限定在程序的最小作用域,不要传递到不须要它的函数中。
6.Context的运行场景
6.1HTTP恳求中的Context经常使用
packagemainimport("fmt""/http""time")funchandler(whttp.ResponseWriter,r*http.Request){ctx:=r.Context()select{case<-time.After(2*time.Second):fmt.Fprintln(w,"Hello,World!")case<-ctx.Done():err:=ctx.Err()fmt.Println("Server:",err)http.Error(w,err.Error(),http.StatusInternalServerError)}}funcmain(){http.HandleFunc("/",handler)http.ListenAndServe(":8080",nil)}
在下面示例中,创立了一个HTTP恳求处置函数handler。
在处置函数中,用r.Context()失掉到恳求的Context,并在其中口头一个耗时的义务。
假设恳求超时,ctx.Done()会接纳到敞开信号,可以在其中处置恳求超时的逻辑。
6.2数据库操作中的Context经常使用
packagemainimport("context""database/sql""fmt""time"_".com/go-sql-driver/")funcmain(){//衔接数据库db,err:=sql.Open("mysql","username:pass@tcp(localhost:3306)/database")iferr!=nil{fmt.Println("数据库衔接失败:",err)return}deferdb.Close()//创立一个Context,设置超时期间为5秒ctx,cancel:=context.WithTimeout(context.Background(),5*time.Second)defercancel()//在Context的超时期间外口头数据库查问rows,err:=db.QueryContext(ctx,"SELECT*FROMusers")iferr!=nil{fmt.Println("数据库查问失败:",err)return}deferrows.Close()//处置查问结果forrows.Next(){//处置每一行数据}}
在下面例子中,经常使用>
packagemainimport("context""fmt""time")typeRequeststruct{IDint}typeResponsestruct{Messagestring}funcmicroservice(ctxcontext.Context,reqChchanRequest,resChchanResponse){for{select{case<-ctx.Done():fmt.Println("Microserviceshuttingdown...")returncasereq:=<-reqCh://模拟处置恳求的耗时操作time.Sleep(2*time.Second)response:=Response{Message:fmt.Sprintf("ProcessedrequestwithID%d",req.ID)}resCh<-response}}}funcmain(){//创立根ContextrootContext:=context.Background()//创立用于恳求和照应的通道reqCh:=make(chanRequest)resCh:=make(chanResponse)//启动微服务gomicroservice(rootContext,reqCh,resCh)//创立带有5秒超时期间的Contextctx,cancel:=context.WithTimeout(rootContext,5*time.Second)defercancel()//发送恳求到微服务fori:=1;i<=3;i++{req:=Request{ID:i}reqCh<-reqselect{case<-ctx.Done():fmt.Println("Requesttimedout!")returncaseres:=<-resCh:fmt.Println(res.Message)}}}
在下面示例中,创立了一个便捷的微服务模拟,它接纳来自reqCh通道的恳求,并将处置结果发送到resCh通道。
在主函数中,用带有5秒超时期间的Context来确保恳求不会有限期期待,同时也能够处置超时的状况。
7.最佳通常与留意事项
7.1防止在函数库中经常使用Context
通常状况下,应该在函数的参数列表中显式传递Context,而不是将Context放在结构体中。
这样做可以使函数的行为愈加明白,防止暗藏传递的Context,提高代码的可读性和可保养性。
7.2防止在结构体中嵌入Context
虽然可以将Context作为结构体的成员嵌入,但这样的做法通常是不介绍的。
由于Context应该是在函数调用的时刻传递,而不是嵌入在结构体中。
假设结构体的方法须要经常使用Context,应该将Context作为参数传递给这些方法。
![Go言语](https://tyye.cn/zb_users/theme/tpure/style/images/lazyload.png)
7.3留意Context的传递门路
在实践运行中,要细心思考Context的传递门路。
若是在多个函数之间传递Context,确保Context的传递门路明晰明了,防止出现歧义和凌乱。
Context的传递门路应该尽量短,不要超越过多的函数调用。
总结
在Go言语中,Context是一个弱小的工具,用于处置恳求的传递、控制和超时等。
经过正当地经常使用Context,可以编写出愈加稳固、高效的异步程序,提高系统的强健性和可保养性。
golang底层用什么语言实现的
golang底层用什么语言实现的
Go runtime的调度器:在了解Go的运行时的scheduler之前,需要先了解为什么需要它,因为我们可能会想,OS内核不是已经有一个线程scheduler了嘛?熟悉POSIX API的人都知道,POSIX的方案在很大程度上是对Unix process进场模型的一个逻辑描述和扩展,两者有很多相似的地方。 Thread有自己的信号掩码,CPU affinity等。但是很多特征对于Go程序来说都是累赘。 尤其是context上下文切换的耗时。另一个原因是Go的废品回
workerman用什么语言实现的
Workerman是一款纯PHP开发的开源高性能的PHP socket 服务器框架。被广泛的用于手机app、移动通讯,微信小程序,手游服务端、网络游戏、PHP聊天室、硬件通讯、智能家居、车联网、物联网等领域的开发。 支持TCP长连接,支持Websocket、HTTP等协议,支持自定义协议。拥有异步Mysql、异步Redis、异步Http、异步消息队列等众多高性能组件
cassandra用什么语言实现的
Cassandra 的名称来源于希腊神话,是特洛伊的一位悲剧性的女先知的名字,因此项目的Logo是一只放光的眼睛。这个项目由就职于Facebook的Avinash Lakshman(也是Amazon Dynamo的作者之一)和Prashant Malik在为Facebook的Inbox编写。2008年,Facebook将项目开源,Cassandra在2009年成为了Apache软件基金会的Incubator项目,并在2010年2月走出孵化器,成为正式的基金会项目。目前这个项目主要由专门进行Cassandra商业化运作的DataStax公司来开发,也有一些来自其他公司或独立的开发者
zookepeer是用什么语言实现的
本文是Jason Wilder对于常见的服务发现项目 Zookeeper , Doozer , Etcd 所写的一篇博客,其原文地址如下: Open-Source Service Discovery 。 服务发现是大多数分布式系统以及面向服务架构(SOA)的一个核心组成部分。
ovation是用什么语言实现的
随你高兴,和语言没有关系.就像你说的这句话可以用中文说,一样可以用随便什么语言表达同样的意思.
SmoothDraw 3是用什么语言实现的
objectMainextendsApp{varreverse_pairs = 0逆序数defmsort[T](cmp:(T, T) => Boolean)(l:List[T]):List[T] = {defmerge(l1:List[T], l2:List[T]):List[T]=(l1, l2)match{case(Nil, _) => l2case(_, Nil) => l1case(x::left1, y::left2) =>if(cmp(x, y))x::merge(left1, l2)else{reverse_pairs += ::merge(l1, left2)}}valn = / 2if(n == 0)return lelse{val(l1, l2) = (n)merge(msort(cmp)(l1), msort(cmp)(l2))}}println(msort((x:Int, y:Int) => x<y)(List(5, 4, 3, 2, 7,6 )))println(reverse_pairs)}
网络用什么编程语言实现的?
应该是Java的技术(jsp/servlet)或PHP,平台应该是Linux/Unix.这个我是从网络的招聘页面上的招聘信息,猜想的。而且Java的面大
Struts1的底层用什么实现的?
struts原理其实就是一个Servlet,只不过有一个中央处理器在配置文件里面,客户端的请求先通过配置文件里面 找到ActionServlet来处理,ActionServlet会根据你的请求来分配具体的Action来处理你,处理完了以后,然后转发页面,显示数据,就这一系列操作。
用verilog语言实现的nand flash
这种题目太可笑了用verilog实现其行为 并给出逻辑门搭建的阵列是很简单但是在不涉及任何工艺的情况下, K9 Flash(本身指的是利用浮栅晶体管雪崩效应写入 隧传效应成批擦出的一种工艺) 没有任何意义何况对于存储器这种阵列逻辑 没有用verilog 来半定制设计的道理从来都是针对foundry工艺库给定的宏进行配置来直接生成可用的各种模型行为模型的话 只要你清楚nand flash的工作原理就行了 很容易
python解释器是用什么语言实现的
用的是python解释器。 首先win+R 运行cmd,如果 python --version不报错,则表明环境正确 python 运行即可
是学好java另外几门编程语言都会学的容易吗?像c语言,c加加,go语言,Python
三种编程语言我都学过,C++和这三门编程语言中,最简单的是Python, 其次是Java, 最难的是C++。 这三种语言都比较容易入门,掌握其基础语法,数据类型,控制结构,面向对象,即可。 c++和java都是面向对象的语言,所以两者间有很多类似的地方,比如封装、继承、多态、重载等一些操作,c++中有STL,标准模板库,将一些常用的东西封装成函数,方便我们调用,并且有了引用,这一操作就是针对c语言的指针,大家都知道指针哪方面其实很难掌握,因为人脑的缘故,指向单个指针的时候可能还能够记忆清楚,但是当面临多个指针,并且有指向指针的指针时,可能就束手无策了,并且malloc的内存很容易忘记释放,或者释放的时间位置不对,但c++中有智能指针,它可以将分配的内存块自动释放,很方便,并且从执行速度方面来说,比java要快一些,因为继承了c语言的许多特性,所以c语言编写的程序,在c++环境下也能够运行,其实更本质的,在一开始没有c++编译环境,c++程序都是转换成c语言,然后在c编译环境下运行。 java的优点很多,使用的范围也更广,类库也极为丰富,在开发的时候可以节省大量的时间,并且因为使用 广泛,许多的东西其实网上就已经有了现成的东西,很方便,如果记忆力较好的话,学习java要更快一些,并且效果要比c++好,对于工作也是,java的工作岗位需求要比c++多很多。
免责声明:本文转载或采集自网络,版权归原作者所有。本网站刊发此文旨在传递更多信息,并不代表本网赞同其观点和对其真实性负责。如涉及版权、内容等问题,请联系本网,我们将在第一时间删除。同时,本网站不对所刊发内容的准确性、真实性、完整性、及时性、原创性等进行保证,请读者仅作参考,并请自行核实相关内容。对于因使用或依赖本文内容所产生的任何直接或间接损失,本网站不承担任何责任。