当前位置: 首页 > news >正文

设计类作品集怎么制作关键词优化快速排名

设计类作品集怎么制作,关键词优化快速排名,广东全屋定制十大名牌,做app和做网站的区别其实对于#xff0c;context来说#xff0c;如果只是用来做并发处理就有些不太合适。因为对于golang来说#xff0c;context应用场景不仅在并发有用#xff0c;并且在网络链接#xff0c;http处理#xff0c;gorm中都有体现。但是其实#xff0c;本质来说。以上这些场景…其实对于context来说如果只是用来做并发处理就有些不太合适。因为对于golang来说context应用场景不仅在并发有用并且在网络链接http处理gorm中都有体现。但是其实本质来说。以上这些场景其实都是并发goroutine 的应用。故在这里我只讲context在并发的情况。 文章目录 ContextContext的出现context的设计思想context的使用初始化首先就是要定义根节点with四系列WithCancelWithDeadlineWithTimeoutWithValue Context Context这个其实在其他语言都有涉及比如 Spirngboot ApplicationContextflutter BuildContextAndroidContextKotlin CoroutineContext.NET CancellationSourceToken 可以说很多很多了。但是他们的用法不尽相同。而 go中的 context 的设计思想以及应用场景非常的新颖。为什么这么说呢这就要说go中最大的特点goroutine 协程。 go以协程而闻名。 而如何有效控制goroutine 协程这个问题有很多不同解释 比如 1有效控制协程之间对于共享变量的控制------------ 加锁操作2有效控制协程之间数据的交互------------------------ channle3有效控制协程之间先后顺序--------------------------- 阻塞selectsycn包4有效控制协程之间错误信息--------------------------- recover、errgroup5有效控制协程之间的嵌套------------------------------ context(今天要重点说明的) 上面的这些1234点在我的并发三部曲中有体现。感兴趣的可以移步 Context的出现 一个场景问题如何在主协程中控制从协程的开启和结束呢 方案一、 用时间去控制很明显这种方式并不是很恰当时间设置过早或者过晚都有问题很难控制 方案二、 提供一个全局变量用这个全局变量去控制从协程的开始和结束 package mainimport (fmtsynctime )var wg sync.WaitGroup var exit boolfunc worker() {for {fmt.Println(worker)time.Sleep(time.Second)if exit {break}}wg.Done() }func main() {wg.Add(1)go worker()time.Sleep(time.Second * 3) // sleep3秒以免程序过快退出exit true // 修改全局变量实现子goroutine的退出wg.Wait()fmt.Println(over) }全局变量方式存在的问题 使用全局变量在跨包调用时不容易统一如果worker中再启动goroutine就不太好控制了 方案三、 既然能通过全局变量的方式去达到控制的目的那么是不是可以用channle 通过通道channle去控制一个局部变量用接收和发送的方式达到控制协程的目的 package mainimport (fmtsynctime )var wg sync.WaitGroupfunc worker(exitChan chan struct{}) { LOOP:for {fmt.Println(worker)time.Sleep(time.Second)select {case -exitChan: // 等待接收上级通知break LOOPdefault:}}wg.Done() }func main() {var exitChan make(chan struct{})wg.Add(1)go worker(exitChan)time.Sleep(time.Second * 3) // sleep3秒以免程序过快退出exitChan - struct{}{} // 给子goroutine发送退出信号close(exitChan)wg.Wait()fmt.Println(over) }管道方式存在的问题 使用全局变量跨包调用时不容易实现规范和统一需要维护一个共用的channel(太麻烦了) 综合 就这些传统控制的手段相信大家看见代码和我的解释一定有所感受但是我要说的是。这些解决方案并非不可行。对于少量的goroutine来说这种方式未尝不可。 但是一旦嵌套了很多层。我们对于这种方式真的能合理控制—达到不 “ 然 ” 吗糊涂混乱的意思大佬除外 任务的 goroutine 层级越深想要自己做退出信号感知和元数据共享就越难 所以我们需要一种优雅的方案来实现这样一种机制 上层任务取消后所有的下层任务都会被取消中间某一层的任务取消后只会将当前任务的下层任务取消而不会影响上层的任务以及同级任务可以线程安全地在 goroutine 之间共享一些任务的元数据 所以为此 Go 官方在1.7 版本引入了 Context 来实现上面阐述的机制 context的设计思想 我们先看源码接口 type Context interface {Deadline() (deadline time.Time, ok bool)Done() -chan struct{}Err() errorValue(key interface{}) interface{} }Context接口包含四个方法 Deadline返回绑定当前context的任务被取消的截止时间如果没有设定期限将返回ok false。Done 当绑定当前context的任务被取消时将返回一个关闭的channel如果当前context不会被取消将返回nil。Err 如果Done返回的channel没有关闭将返回nil;如果Done返回的channel已经关闭将返回非空的值表示任务结束的原因。如果是context被取消Err将返回Canceled如果是context超时Err将返回DeadlineExceeded。Value 返回context存储的键值对中当前key对应的值如果没有对应的key,则返回nil。 Done方法返回的channel正是用来传递结束信号以抢占并中断当前任务Deadline方法指示一段时间后当前goroutine是否会被取消Err方法来解释goroutine被取消的原因 如果当前Context被取消就会返回Canceled错误如果当前Context超时就会返回DeadlineExceeded错误 Value则用于获取特定于当前任务树的额外信息 首先我要说的是context的结构是一个树状结构。为了方便找到根节点有定义了一个结构emptyCtx emptyCtx是一个int类型的变量但实现了context的接口。emptyCtx没有超时时间不能取消也不能存储任何额外信息所以emptyCtx用来作为context树的根节点。 // An emptyCtx is never canceled, has no values, and has no deadline. It is not // struct{}, since vars of this type must have distinct addresses. type emptyCtx intfunc (*emptyCtx) Deadline() (deadline time.Time, ok bool) {return }func (*emptyCtx) Done() -chan struct{} {return nil }func (*emptyCtx) Err() error {return nil }func (*emptyCtx) Value(key interface{}) interface{} {return nil }func (e *emptyCtx) String() string {switch e {case background:return context.Backgroundcase todo:return context.TODO}return unknown empty Context }var (background new(emptyCtx)todo new(emptyCtx) ) func Background() Context {return background } func TODO() Context {return todo }但我们一般不会直接使用emptyCtx而是使用由emptyCtx实例化的两个变量分别可以通过调用Background和TODO方法得到 每次要在Context链路上增加要携带的键值对时都要在上级Context的基础上新建一个 valueCtx 存储键值对切只能增加不能修改读取 Context 上的键值又是一个幂等的操作所以 Context 就这样实现了线程安全的数据共享机制且全程无锁不会影响性能。 cancelCtx结构体 type cancelCtx struct {Contextmu sync.Mutex // protects following fieldsdone chan struct{} // created lazily, closed by first cancel callchildren map[canceler]struct{} // set to nil by the first cancel callerr error // set to non-nil by the first cancel call }type canceler interface {cancel(removeFromParent bool, err error)Done() -chan struct{} }cancelCtx中也有一个context变量作为父节点变量done表示一个channel用来表示传递关闭信号children表示一个map存储了当前context节点下的子节点err用于存储错误信息表示任务结束的原因 valueCtx结构体 type valueCtx struct {Contextkey, val interface{} }func (c *valueCtx) Value(key interface{}) interface{} {if c.key key {return c.val}return c.Context.Value(key) }valueCtx利用一个Context类型的变量来表示父节点context所以当前context继承了父context的所有信息 valueCtx类型还携带一组键值对也就是说这种context可以携带额外的信息valueCtx实现了Value方法用以在context链路上获取key对应的值如果当前context上不存在需要的key,会沿着context链向上寻找key对应的值直到根节点 timerCtx结构体 type timerCtx struct {cancelCtxtimer *time.Timer // Under cancelCtx.mu.deadline time.Time }func (c *timerCtx) Deadline() (deadline time.Time, ok bool) {return c.deadline, true }func (c *timerCtx) cancel(removeFromParent bool, err error) {将内部的cancelCtx取消c.cancelCtx.cancel(false, err)if removeFromParent {// Remove this timerCtx from its parent cancelCtxs children.removeChild(c.cancelCtx.Context, c)}c.mu.Lock()if c.timer ! nil {取消计时器c.timer.Stop()c.timer nil}c.mu.Unlock() }timerCtx内部使用cancelCtx实现取消另外使用定时器timer和过期时间deadline实现定时取消的功能。timerCtx在调用cancel方法会先将内部的cancelCtx取消如果需要则将自己从cancelCtx祖先节点上移除最后取消计时器。 除了Context 接口外还定义了一个叫做 canceler 的接口实现了它的类型即为带取消功能的 Context。 emptyCtx 什么属性也没有啥也不能干。valueCtx 只能携带一个键值对且依附在上一级 Context 上。timerCtx 继承自 cancelCtx 他们都是带取消功能的 Context。 除了emptyCtx其他类型的 Context 都依附在上级 Context 上 经过这个结构设计如果要在整个任务链路上取消某个cancelCtx时就能做到既取消自己也把下级所有的cancelCtx都取消掉同时还不会影响到上级和同级的其他节点。 我们让每个 goroutine 都携带了 Context 那些做子任务的goroutine只要监听了这些子 cancelCtx 也就能收到信号结束自己的运行即通过Context 完成上级goroutine对下级 goroutine 的取消控制。 面对不同层级的goroutine的取消条件不同的情况代码里只需要监听传递到 goroutine 里的 Context 就能做到免除了监听多个信号的繁琐 针对Context的使用建议Go官方提到了下面几点 不要将 Context 塞到结构体里。直接将 Context 类型作为函数的第一参数而且一般都命名为 ctx。不要向函数传入一个 nil 的 context如果你实在不知道传什么标准库的TODO方法给你准备好了一个 emptyCtx。 一般在初始化用Background和TODO只是用于不同场景下 Background通常被用于主函数、初始化以及测试中作为一个顶层的context也就是说一般我们创建的context都是基于BackgroundTODO是在不确定使用什么context的时候才会使用 不要把本应该作为函数参数的类型塞到 context 中context 存储的应该是一些在 goroutine 共享的数据比如Server的信息等等 context的使用 初始化首先就是要定义根节点 Go内置两个函数Background()和TODO()这两个函数分别返回一个实现了Context接口的background和todo。 我们代码中最开始都是以这两个内置的上下文对象作为最顶层的partent context衍生出更多的子上下文对象。 Background()主要用于main函数、初始化以及测试代码中作为Context这个树结构的最顶层的Context也就是根Context。TODO()它目前还不知道具体的使用场景如果我们不知道该使用什么Context的时候可以使用这个。 background和todo本质上都是emptyCtx结构体类型是一个不可取消没有设置截止时间没有携带任何值的Context。 with四系列 WithCancel func WithCancel(parent Context) (ctx Context, cancel CancelFunc)WithCancel返回带有新Done通道的父节点的副本。当调用返回的cancel函数或当关闭父上下文的Done通道时将关闭返回上下文的Done通道无论先发生什么情况。 取消此上下文将释放与其关联的资源因此代码应该在此上下文中运行的操作完成后立即调用cancel。 func gen(ctx context.Context) -chan int {dst : make(chan int)n : 1go func() {for {select {case -ctx.Done():return // return结束该goroutine防止泄露case dst - n:n}}}()return dst} func main() {ctx, cancel : context.WithCancel(context.Background())defer cancel() // 当我们取完需要的整数后调用cancelfor n : range gen(ctx) {fmt.Println(n)if n 5 {break}} }代码解释 gen函数在单独的goroutine中生成整数并将它们发送到返回的通道。 gen的调用者在使用生成的整数之后需要取消上下文以免gen启动的内部goroutine发生泄漏。 WithDeadline func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc)返回父上下文的副本并将deadline调整为不迟于d(设置的时间)。如果父上下文的deadline已经早于d设置的时间则WithDeadline(parent, d)在语义上等同于父上下文。当截止日过期时当调用返回的cancel函数时或者当父上下文的Done通道关闭时返回上下文的Done通道将被关闭以最先发生的情况为准。 取消此上下文将释放与其关联的资源因此代码应该在此上下文中运行的操作完成后立即调用cancel。 func main() {d : time.Now().Add(50 * time.Millisecond)ctx, cancel : context.WithDeadline(context.Background(), d)// 尽管ctx会过期但在任何情况下调用它的cancel函数都是很好的实践。// 如果不这样做可能会使上下文及其父类存活的时间超过必要的时间。defer cancel()select {case -time.After(1 * time.Second):fmt.Println(overslept)case -ctx.Done():fmt.Println(ctx.Err())} }代码解释 定义了一个50毫秒之后过期的deadline然后我们调用context.WithDeadline(context.Background(), d)得到一个上下文context和一个取消函数cancel然后使用一个select让主程序陷入等待等待1秒后打印overslept退出或者等待ctx过期后退出。 代码因为ctx 50毫秒后就会过期所以ctx.Done()会先接收到context到期通知并且会打印ctx.Err()的内容 WithTimeout WithTimeout返回WithDeadline(parent, time.Now().Add(timeout)) func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)取消此上下文将释放与其相关的资源因此代码应该在此上下文中运行的操作完成后立即调用cancel通常用于数据库或者网络连接的超时控制 // context.WithTimeoutvar wg sync.WaitGroupfunc worker(ctx context.Context) { LOOP:for {fmt.Println(db connecting ...)time.Sleep(time.Millisecond * 10) // 假设正常连接数据库耗时10毫秒select {case -ctx.Done(): // 50毫秒后自动调用break LOOPdefault:}}fmt.Println(worker done!)wg.Done() }func main() {// 设置一个50毫秒的超时ctx, cancel : context.WithTimeout(context.Background(), time.Millisecond*50)wg.Add(1)go worker(ctx)time.Sleep(time.Second * 5)cancel() // 通知子goroutine结束wg.Wait()fmt.Println(over) }WithValue WithValue 返回与 key 关联的值为 val 的 parent 副本 func WithValue(parent Context, key, val interface{}) ContextWithValue返回父节点的副本其中与key关联的值为val。仅对API和进程间传递请求域的数据使用上下文值而不是使用它来传递可选参数给函数。 所提供的键必须是可比较的并且不应该是string类型或任何其他内置类型以避免使用上下文在包之间发生冲突。WithValue的用户应该为键定义自己的类型。为了避免在分配给interface{}时进行分配上下文键通常具有具体类型struct{}。或者导出的上下文关键变量的静态类型应该是指针或接口 // context.WithValuetype TraceCode stringvar wg sync.WaitGroupfunc worker(ctx context.Context) {key : TraceCode(TRACE_CODE)traceCode, ok : ctx.Value(key).(string) // 在子goroutine中获取trace codeif !ok {fmt.Println(invalid trace code)} LOOP:for {fmt.Printf(worker, trace code:%s\n, traceCode)time.Sleep(time.Millisecond * 10) // 假设正常连接数据库耗时10毫秒select {case -ctx.Done(): // 50毫秒后自动调用break LOOPdefault:}}fmt.Println(worker done!)wg.Done() }func main() {// 设置一个50毫秒的超时ctx, cancel : context.WithTimeout(context.Background(), time.Millisecond*50)// 在系统的入口中设置trace code传递给后续启动的goroutine实现日志数据聚合ctx context.WithValue(ctx, TraceCode(TRACE_CODE), 12512312234)wg.Add(1)go worker(ctx)time.Sleep(time.Second * 5)cancel() // 通知子goroutine结束wg.Wait()fmt.Println(over) }最后在强调一下 推荐以参数的方式显示传递Context以Context作为参数的函数方法应该把Context作为第一个参数。给一个函数方法传递Context的时候不要传递nil如果不知道传递什么就使用context.TODO()Context的Value相关方法应该传递请求域的必要数据不应该用于传递可选参数Context是线程安全的可以放心的在多个goroutine中传递
http://www.sadfv.cn/news/268672/

相关文章:

  • 安徽索凯特建设工程有限公司网站sem竞价托管公司
  • 为什么学习wordpress处理器优化软件
  • 电子商务建立网站前期准备设计师网上接私单app
  • 北京好网站制作公司哪家好空间站免费版下载
  • 网站建设要用H5吗北京市430场新闻发布会
  • 如何建设社区网站首页网站制作一条龙全包
  • 市场营销策划方案格式模板电商seo是什么
  • 海兴县建设工程招标信息网站51栗子
  • 网站突然被降权访问不到自己做的网站
  • 论坛网站html模板做网站人才
  • 工商注册官方网站室内设计师需要学什么软件
  • 网站模仿侵权安卓程序开发用什么软件
  • 手机网站支付西安官网优化报价
  • 做企业网站找哪家天津市网站建设管理办法
  • 北京网站制作 建设推广wordpress评论框样式
  • 从零开始做电影网站安徽网站建设怎么样
  • 网站设计中遇到的问题企业网站建设会计分录
  • 本地的响应式网站建设开发第一个app应用程序
  • 优的网站建设明细报价表盐山县网站建设公司
  • 开发网站公司如何运营门户网登录入口
  • 做数据表格的网站山西又增一例在忻州
  • 哈尔滨公司网站团队开发网站公司收费
  • 昆明网站开发公司电话网页设计与网站建设考试名词解释2019
  • 无锡建设信息中心网站wordpress 收邮件
  • 东莞做外贸网站公司钢结构
  • 手机网站 分享按钮甘肃张掖网站建设
  • 南通北京网站建设东圃做网站的公司
  • 一个网站可以做多少弹窗广告抖音推广怎么做
  • 建设家装网站企业网站策划过程
  • 建设企业网站体会wordpress文章页面没有格式调整